A single tall photograph pinned with position sticky, captioned without a rule, while a column of eyebrow-led notes scrolls past it, each note after the first opening on its own hairline.
One photograph holds its position while a numbered set of notes scrolls past it. Each note opens on its own eyebrow and rule, and the outline CTA closes the column rather than the section.
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/feature250?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/feature250?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/feature250.tsx plus the badge7 eyebrow and button12 pill button it uses.
The installed file exports feature250Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Feature250, feature250Demo } from "@/components/beste/block/feature250";
export default function Page() {
return <Feature250 {...feature250Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Feature250 } from "@/components/beste/block/feature250";
export default function Page() {
return (
<Feature250
badge={{ label: "One building, four notes" }}
heading="Read down the page, the picture stays where it is."
image={{
src: "/case/ceiling.jpg",
alt: "Vaulted ceiling with repeating ribs",
caption: "Atrium ceiling, before the signage went up",
}}
notes={[
{
index: "Note one",
title: "The ceiling decided the type size",
description: "Nine metres of air means anything under forty millimetres disappears.",
},
{
index: "Note two",
title: "The ribs decided the spacing",
description: "Every sign lines up with a structural rib.",
},
]}
button={{ label: "Read the full case", href: "/work/atrium" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string } | – | Eyebrow label rendered as a Badge7 |
heading | string | – | Section heading above the two columns |
image | StickyImage | – | The photograph that sticks, plus its caption |
notes | FeatureNote[] | [] | Notes in the scrolling column, each with its own eyebrow |
button | ActionButton | – | Outline Button12 at the end of the notes column |
className | string | – | Extra classes for the outer <section> |
type StickyImage = {
src: string;
alt: string;
caption: string;
};
type FeatureNote = {
index: string;
title: string;
description: string;
};
type ActionButton = {
label: string;
href: string;
};md:sticky md:top-24 md:self-start; self-start is the part that matters, because a stretched grid item cannot stick at all.md. On a phone the photograph is simply the first thing in the column, so the section reads as picture then notes.border-t pt-6, which keeps the column from opening on a stray rule directly under the heading.Badge7, so the sequence uses the same eyebrow treatment as the section itself instead of inventing a second label style.aspect-[4/5], tall enough that the sticky frame still fills its side of the grid while four notes scroll past it.feature227
Sticky left intro paired with a stacked, numbered list of feature blocks, each with a title, description, and small image.
feature229
Interactive feature section with an eyebrow, big heading and description above a two-column layout: a single-collapsible accordion of feature items on the left and a sticky image on the right that swaps to the active item's image on click.
feature209
Sticky intro column beside a scrollable stack of numbered service blocks.