A two column contact section. Labeled groups for address, phone numbers, fax and email sit on the left, and a form with first and last name side by side, email, subject, message and a full width send button sits on the right. A wide embedded Google Map runs underneath.
A two column contact section: labeled groups for address, phone numbers, fax and email on the left, a form with first and last name side by side, email, subject, message and a full width send button on the right, and a wide embedded Google Map underneath.
Upgrade to Pro
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://beste.dev/r/contact7?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/contact7?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/contact7.tsx plus the shadcn button, input, label and textarea primitives it uses.
The installed file exports contact7Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Contact7, contact7Demo } from "@/components/beste/block/contact7";
export default function Page() {
return <Contact7 {...contact7Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Contact7 } from "@/components/beste/block/contact7";
export default function Page() {
return (
<Contact7
infoHeading="Contact details"
groups={[
{ title: "Address", lines: [{ label: "214 Atlantic Avenue, Brooklyn, NY 11201" }] },
{ title: "Phone", lines: [{ label: "(718) 555 0179", href: "tel:+17185550179" }] },
{ title: "Email", lines: [{ label: "[email protected]", href: "mailto:[email protected]" }] },
]}
formHeading="Contact form"
fields={[
{ name: "firstName", label: "First name", width: "half", required: true },
{ name: "lastName", label: "Last name", width: "half", required: true },
{ name: "email", label: "Email", type: "email", required: true },
{ name: "message", label: "Message", type: "textarea", required: true },
]}
submitLabel="Send"
map={{
embedUrl: "https://www.google.com/maps?q=Atlantic+Avenue+Brooklyn+NY&output=embed",
title: "Office location on Google Maps",
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
infoHeading | string | – | Heading above the contact groups |
groups | ContactGroup[] | [] | Labeled groups of contact lines |
formHeading | string | – | Heading above the form |
fields | FormField[] | [] | Form fields in order |
submitLabel | string | – | Text of the submit button; the button is hidden without it |
map | { embedUrl: string; title: string } | – | Google Maps embed shown under both columns |
className | string | – | Extra classes for the outer section |
type ContactGroup = {
title: string;
lines: ContactLine[];
};
type ContactLine = {
label: string;
href?: string;
};
type FormField = {
name: string;
label: string;
type?: "text" | "email" | "tel" | "textarea";
width?: "half" | "full";
required?: boolean;
};dl, with each group title as a dt and every line as its own dd, so a group can hold several phone numbers or emails.href becomes a plain a in the primary color, which suits mailto: and tel: targets; lines without one stay plain text.label as the placeholder and keeps a screen reader only Label. Field ids come from useId, so two of these on one page keep every label tied to its own input.width: "half" puts a field in a two column row from sm; every other field takes the full width. type: "textarea" renders a Textarea instead of an Input.map.embedUrl, any Google Maps link with output=embed works, or the src from the Share and Embed a map dialog. The frame is 4:3 on phones and 21:9 from md, and loads lazily.preventDefault() and logs the field values with console.log; nothing is sent until you wire it up.Wiring the form up
This block ships the form markup only; state, validation, and submit are yours to add. Our guide wires the shadcn Field primitives to React Hook Form, TanStack Form, and Formisch on one field system.