Weddings
Once a month between spring and autumn we close the hotel to everyone else. You get all twelve rooms, the olive grove for dinner and the cliff for the vows, and one person who looks after every detail.


Dinner in the grove, vows on the cliff
A wedding and exclusive-use section for a small hotel: a serif heading and an intro beside two overlapping photographs that drift past each other as you scroll, with a request-a-proposal pill and the planner's portrait, name and role.
A wedding section with a serif heading, an intro, a proposal pill and the planner's portrait on the left, and two overlapping photographs on the right that move in opposite directions as you scroll, with a short caption under them.
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/hotel13?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/hotel13?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/hotel13.tsx plus the button22 sliding-marker pill for the proposal button and the text1 word stagger for the heading.
The installed file exports hotel13Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Hotel13, hotel13Demo } from "@/components/beste/block/hotel13";
export default function Page() {
return <Hotel13 {...hotel13Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hotel13 } from "@/components/beste/block/hotel13";
export default function Page() {
return (
<Hotel13
eyebrow="Weddings"
heading="The whole house, for the people you love most."
description="Once a month we close the hotel to everyone else: all twelve rooms, the olive grove for dinner and the cliff for the vows."
button={{ label: "Request a proposal", href: "/weddings/proposal", tone: "dark" }}
planner={{
name: "Jessica Pratt",
role: "Looks after every wedding",
avatar: { src: "https://images.unsplash.com/photo-1544005313-94ddf0286df2?w=200&h=200&fit=crop", alt: "Portrait of Jessica Pratt" },
}}
images={{
main: { src: "https://oud.pics/b/hotel/ostria-wedding-table.webp", alt: "A candlelit wedding table in an olive grove at dusk" },
inset: { src: "https://oud.pics/b/hotel/ostria-ceremony-cliff.webp", alt: "Chairs facing an olive branch arch on a clifftop" },
}}
caption="Dinner in the grove, vows on the cliff"
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Uppercase line above the heading |
heading | string | – | Serif heading, through Text1 |
description | string | – | Intro paragraph under the heading |
button | ActionButton | – | Button22 pill for the proposal request |
planner | Planner | – | Planner's name, role and optional round portrait |
images | Images | – | The large main photograph and the bordered inset |
caption | string | – | Small line under the photographs |
className | string | – | Extra classes for the outer <section> |
type ActionButton = {
label: string;
href: string;
tone?: "primary" | "light" | "dark" | "outline";
};
type Planner = {
name: string;
role: string;
avatar?: { src: string; alt: string };
};
type Images = {
main: { src: string; alt: string };
inset: { src: string; alt: string };
};whileInView (once), the inset 0.2s after the main, and each fades in from a 24px blur only after the file has loaded.sm and 4:5 again on large screens.images the whole photo column (and the caption) is skipped. The planner avatar is optional and the button tone falls back to dark.