Just ask
Tell the house what kind of day you want. Most of these can happen by tomorrow, a few by this afternoon.
A day on the caiqueThree coves, a skipper who grew up here, lunch on boardA day ahead
Supper in the vineyardA table between the vines and a winemaker who stays for a glassTwo days ahead
A massage on your terraceIsland oils, a folding table and the sound of the seaSame day
The chef, cooking for twoDinner made in front of you on the pass, with the chef choosingA day ahead
A walk to the old templeWith a guide who knows which goat paths are shadedSame dayA ruled list of things a small hotel will arrange, set in large serif lines with a short note and how much notice each needs: hovering a row dims the others and a tilted photograph follows the pointer across the list, swapping to match the request. Phones get a small thumbnail on every row instead.
A ruled list of concierge requests in large serif lines, each with a note and how much notice it needs: hovering a row dims the others while a tilted photograph trails the pointer across the list and swaps to match the request.
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/hotel28?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://beste.dev/r-base/hotel28?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/hotel28.tsx plus the button22 sliding-marker pill for the closing button and the text1 word stagger for the heading.
The installed file exports hotel28Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Hotel28, hotel28Demo } from "@/components/beste/block/hotel28";
export default function Page() {
return <Hotel28 {...hotel28Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hotel28 } from "@/components/beste/block/hotel28";
export default function Page() {
return (
<Hotel28
eyebrow="Just ask"
heading="Things we are happy to arrange."
description="Most of these can happen by tomorrow, a few by this afternoon."
requests={[
{
title: "A day on the caique",
note: "Three coves, a local skipper, lunch on board",
lead: "A day ahead",
href: "/concierge/boat",
image: { src: "https://oud.pics/b/hotel/ostria-boat-cove.webp", alt: "A wooden boat in a turquoise cove" },
},
{
title: "A massage on your terrace",
note: "Island oils and the sound of the sea",
lead: "Same day",
href: "/concierge/massage",
image: { src: "https://oud.pics/b/hotel/ostria-treatment-room.webp", alt: "A linen massage table beside a bright window" },
},
]}
button={{ label: "Write to the concierge", href: "mailto:[email protected]", tone: "dark" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small uppercase line above the heading |
heading | string | – | Serif <h2>, staggered word by word through Text1 |
description | string | – | Paragraph at the right of the header |
requests | ConciergeRequest[] | [] | The list rows, each a link |
button | ActionButton | – | Pill action under the list, dark tone when none is set |
className | string | – | Extra classes for the outer <section> |
type ConciergeRequest = {
title: string;
note: string;
lead: string;
href: string;
image: { src: string; alt: string };
};
type ActionButton = {
label: string;
href: string;
tone?: "primary" | "light" | "dark" | "outline";
};lead text is hidden below the small breakpoint, leaving only the arrow.alt, aria-hidden), so image.alt is not read out in this block.