A pinned scroll hero for an architecture studio built on the expanding-frame component: a huge two-line semibold headline sits above and below a small rounded photograph, and as the page scrolls the lines part to the left and right while the photograph grows to fill the whole screen, its corners easing square and the picture settling from a close zoom to its full view. Once the photograph is full, the studio line, an intro, an Arrow Pill and an underline link settle in at the lower left over a soft shade. Every frame setting passes through the frame prop. Reduced motion shows the full photograph with the copy.
A pinned scroll hero built on the expanding-frame component: a huge two-line headline sits above and below a small rounded photograph, and as the page scrolls the lines part left and right while the photo grows to fill the screen, its corners easing square and its zoom settling, before an eyebrow, an intro and two buttons settle in at the lower left.
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/hero253?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/hero253?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/hero253.tsx plus the expanding-frame component and the button23 and button2 buttons it uses.
The installed file exports hero253Demo alongside the block: the exact props behind the preview above. Spread it to get a working hero in one line.
import { Hero253, hero253Demo } from "@/components/beste/block/hero253";
export default function Page() {
return <Hero253 {...hero253Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hero253 } from "@/components/beste/block/hero253";
export default function Page() {
return (
<Hero253
eyebrow="Architects in Lisbon and Accra"
description="Houses, schools and public rooms drawn around the path of the sun."
buttons={[
{ label: "Start a project", href: "/contact" },
{ label: "See our work", href: "/work" },
]}
frame={{
lines: ["Built around", "the light."],
imageSrc: "https://images.unsplash.com/photo-1518005020951-eccb494ad742?w=2400&q=80",
imageAlt: "Curved white bands of a building rising around an opening of blue sky",
startWidth: 0.3,
radius: 28,
zoom: 1.3,
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
eyebrow | string | – | Small line in the overlay once the photo is full |
description | string | – | Intro in the overlay |
buttons | ActionButton[] | [] | The first renders as a light Button23 arrow pill, the rest as Button2 underline links |
frame | Omit<ExpandingFrameProps, "as" | "className" | "children" | "progress" | "autoplay"> | – | Forwards the ExpandingFrame component's props: lines, imageSrc, imageAlt, startWidth, radius, zoom, speed, paused, lineClassName. The headline lives here as lines |
className | string | – | Extra classes for the outer <section> |
type ActionButton = {
label: string;
href: string;
};heading prop: the two headline lines come from frame.lines and are rendered as a visually hidden h1, with the moving lines hidden from screen readers.h-[240svh] with a sticky frame, and the opening maps scroll progress from 0.04 to 0.72 onto 0 to 1.aria-hidden and ignores the pointer.clip-path inset with rounded corners rather than resizing the image, so the photo never reflows.md and up) keeps the white overlay text legible in every theme, while the headline lines on the page follow the theme's foreground.