Letters from the island
When the house opens, when the figs are ripe, when the boats come out of the water. One recipe from the kitchen each time, and nothing else.
Leave whenever you like, with one click at the bottom of any letter.
A centered newsletter section for a small hotel under a line-drawn postage stamp: the perforated stamp, its frame and an olive branch draw themselves in, centered above a serif heading, a short line and an email field with a signup button on one row.
A centered newsletter section where a perforated postage stamp, its inner frame and an olive branch draw themselves in above a serif heading, a short line and an email field with a signup button on one row.
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/hotel51?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/hotel51?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/hotel51.tsx plus the button22 sliding-marker pill used as the submit button, the text1 word stagger used for the heading and the shadcn/ui input primitive behind the email field.
The installed file exports hotel51Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Hotel51, hotel51Demo } from "@/components/beste/block/hotel51";
export default function Page() {
return <Hotel51 {...hotel51Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hotel51 } from "@/components/beste/block/hotel51";
export default function Page() {
return (
<Hotel51
eyebrow="Letters from the island"
heading="Four letters a year, written at the kitchen table"
description="One recipe from the kitchen each time, and nothing else."
stamp={{ place: "Paros" }}
form={{
action: "/api/newsletter",
label: "Email address",
placeholder: "Your email",
submitLabel: "Send me the letters",
note: "Leave whenever you like, with one click at the bottom of any letter.",
}}
labels={{ drawing: "Line drawing of a postage stamp with an olive branch" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small line above the heading |
heading | string | – | Centered section heading, through Text1 |
description | string | – | Paragraph under the heading |
stamp | Stamp | – | Place name printed in the stamp's corner |
form | SignupForm | – | The email form and the note under it |
labels | Labels | {} | Accessible name for the stamp drawing |
className | string | – | Extra classes for the outer <section> |
type Stamp = {
place: string;
};
type SignupForm = {
action: string;
label: string;
placeholder: string;
submitLabel: string;
note?: string;
};
type Labels = {
drawing?: string;
};method="post" to form.action, sending a single required field named email (type email, so the browser validates the address before submitting).form.label is rendered as a visually hidden <label> tied to the input through a generated id; the visible hint is the placeholder.stamp the drawing renders with no place name; without form neither the form nor its note renders.Wiring the form up
The form posts to the action you pass. To validate on the client and handle submission in React instead, see React Hook Form, TanStack Form, and Formisch.