Sleeper trains across Europe
Private cabins, linen sheets and a dining car that stays open past midnight. Eleven overnight routes, no airport queues and a real breakfast on arrival.
A night-train hero built around the split-flap component: a dark departure board of CSS 3D flaps that flick through random glyphs, rippling across the columns before settling on each phrase in capitals, cycling through a list of headlines. Below the board sit the headline, a short intro, an amber Arrow Pill and an underline link. Every board setting passes through the board prop; flips animate transforms only from a loop that sleeps between phrases, it pauses offscreen, and reduced motion shows the first phrase without flipping.
A hero built around the split-flap component: a departure board of CSS 3D flaps that flick through random glyphs in a ripple before settling on each phrase, cycling through a list, above a headline, an intro, a primary Arrow Pill and an underline link.
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/hero219?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/hero219?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/hero219.tsx plus the split-flap board and the button23 and button2 buttons it uses.
The installed file exports hero219Demo alongside the block: the exact props behind the preview above. Spread it to get a working hero in one line.
import { Hero219, hero219Demo } from "@/components/beste/block/hero219";
export default function Page() {
return <Hero219 {...hero219Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hero219 } from "@/components/beste/block/hero219";
export default function Page() {
return (
<Hero219
eyebrow="Sleeper trains across Europe"
heading="Close the curtain in one capital, open it in another."
description="Private cabins, linen sheets and a dining car that stays open past midnight."
buttons={[
{ label: "Find a cabin", href: "/cabins" },
{ label: "See all routes", href: "/routes" },
]}
board={{
phrases: ["Sleep in Paris, wake in Vienna", "Lisbon to Madrid, 22:05"],
columns: 15,
rows: 4,
interval: 5200,
uppercase: true,
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Muted line above the board |
heading | string | – | Headline under the board, rendered as the page h1 |
description | string | – | Intro to the right of the headline from lg |
buttons | ActionButton[] | [] | The first renders as a primary Arrow Pill (Button23), the rest as underline links (Button2) |
board | Omit<SplitFlapProps, "className"> | – | Forwards the SplitFlap props from the split-flap component, including the required phrases plus columns, rows, interval, flips, stagger, capitals, the flap, ink and split colors and paused |
className | string | – | Extra classes for the outer <section> |
type ActionButton = {
label: string;
href: string;
};board is set and board.phrases has at least one entry; it sits in a rounded near-black panel with a faint inner ring, so the board reads as a physical object on any theme.flips random glyphs before settling, and stagger sets how far the ripple travels across the columns.bg-background, text-foreground, text-muted-foreground, primary pill); only the board keeps its own flap, ink and split colors.