Get in touch
Every message is read by a practitioner, not a form robot, and answered within a working day.
The classic contact section: a serif heading that settles in word by word, an intro and a ruled contact sheet on the left, and a plain form with name, email and message fields and a sliding-marker pill on the right, with no panel around it.
A plain contact section: a heading that settles in word by word over a ruled list of contact lines, beside a name, email and message form that ends on a pill and a one-line privacy note.
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://ui.beste.co/r/booking32?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/booking32?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/booking32.tsx, the shadcn input, label, and textarea primitives the form is built on, and the button22 sliding-marker pill and the text1 word stagger it uses.
The installed file exports booking32Demo alongside the block: the exact props behind the preview above. Spread it to get a working contact form in one line.
import { Booking32, booking32Demo } from "@/components/beste/block/booking32";
export default function Page() {
return <Booking32 {...booking32Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Booking32 } from "@/components/beste/block/booking32";
export default function Page() {
return (
<Booking32
eyebrow="Get in touch"
heading="Write as much or as little as you like."
description="Every message is read by a practitioner, not a form robot."
contacts={[
{ label: "Email", value: "hello@beste.co", href: "mailto:hello@beste.co" },
{ label: "Phone", value: "+351 21 000 0000" },
]}
form={{
name: "Your name",
email: "Email",
message: "What would you like to say?",
button: "Send the message",
note: "We never share your details with anyone.",
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small-caps line above the heading |
heading | string | – | Section heading, rendered as an h2 through Text1 |
description | string | – | Intro paragraph under the heading |
contacts | ContactLine[] | [] | Ruled contact rows; a row with href becomes a link |
form | Booking32Form | – | Every string in the form; the whole form is skipped when unset |
className | string | – | Extra classes for the outer <section> |
type ContactLine = {
label: string;
value: string;
href?: string;
};
type Booking32Form = {
name: string;
email: string;
message: string;
button: string;
note: string;
};href on a contact line is what makes it clickable, so an email or a phone number can carry mailto: or tel: while an address stays plain text in the same list.a elements rather than the router Link, which is correct for mailto: and tel: targets that should never be handled by client-side navigation.dl on a three-column grid with the value spanning two, so a long address wraps under itself instead of pushing its label out of line.useId, so two of these on one page keep each Label pointing at its own input.sm, while the message keeps the full width, which is the shape a message form wants: short answers side by side, the long one on its own.form leaves a usable contact section on its own, with just the heading and the ruled lines.preventDefault() on submit; no state is collected and 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.
booking30
A booking section: a serif heading that settles in word by word over the intro, a ruled contact sheet and a practitioner avatar line, beside a calm request form with name and email fields, pill choices for session type and preferred time, a message box and a sliding-marker pill to send.
booking31
A visit-us section: a photograph drifting inside its frame on the left, and on the right a serif heading that settles in word by word, an intro, a ruled sheet with the serif address, directions and opening hours, a sliding-marker pill and a text link.
booking33
A booking chooser: a serif heading that settles in word by word and an intro, then a ruled list of session types on the left that swaps, with a soft blur, the muted detail card on the right showing a serif title, a description, a fact row and a sliding-marker pill.
booking24
An interactive appointment picker: a hairline panel pairing a selectable service list with a scrollable day strip and a time slot grid that marks unavailable times, beside a full-height provider photo with a gradient name card, closing on a live summary bar and confirm action.