Browser Frame Hero
A hero with one large browser-style device frame filling the right side, which straightens and scales up from a slight tilt as the page scrolls, holding any product screen you put inside.
A landing-page hero: an eyebrow, title, subtitle and two CTAs on the left, and one large device frame filling the right side — either a browser (three dots + URL pill) or a laptop (screen + base). As the section enters the viewport, the frame turns from a slight backward lean and side angle to face the viewer and scales up to full size with the scroll, finishing within the first 40% of scroll progress and holding there; the soft shadow under it fades along with the angle. Put your own screenshot or component inside; without one, it draws a placeholder dashboard.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add browser-frame-hero.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<BrowserFrameHero/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/browser-frame-hero.en.jsonOr, once registries are configured in components.json, install it as @webberui/browser-frame-hero.
Usage
import { BrowserFrameHero } from "@/components/ui/browser-frame-hero";
<BrowserFrameHero
eyebrow="Lanyun Ops"
title="One screen to check before you open the shop"
subtitle="Revenue, orders and repeat rate on a single screen."
primaryAction={{ label: "Try it free for 14 days", href: "/signup" }}
secondaryAction={{ label: "Take the tour", href: "/tour" }}
url="app.example.com"
frameLabel="Ops dashboard screenshot"
>
<img src="/screens/dashboard.png" alt="" className="h-full w-full object-cover" />
</BrowserFrameHero>Inside a nested scroll container
By default the component tracks window scroll. When it sits inside a fixed-height overflow-y-auto container, pass that container's ref to container. The frame's tilt and scale follow how far the hero has scrolled through the container.
const scrollerRef = React.useRef<HTMLDivElement>(null);
<div ref={scrollerRef} className="h-[400px] overflow-y-auto">
<BrowserFrameHero container={scrollerRef} />
</div>When the window itself is the scroll container, container can be omitted and behavior is unchanged.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Main title (required) |
eyebrow | ReactNode | — | Small label above the title |
subtitle | ReactNode | — | Supporting text below the title |
primaryAction | BrowserFrameHeroAction | — | Primary button with the accent background |
secondaryAction | BrowserFrameHeroAction | — | Secondary outlined button |
as | "h1" | "h2" | "h1" | Heading level |
minHeight | number | 560 | Minimum section height (px) |
variant | "browser" | "laptop" | "browser" | Device frame style: browser or laptop |
url | string | "app.example.com" | Text inside the browser URL pill |
tilt | number | 12 | Initial maximum tilt (deg); rotateX goes from this value to 0, rotateY from minus 2/3 of it |
bleed | boolean | true | From md up, the frame extends past the container's right edge and is clipped by the section |
images | BrowserFrameHeroImage[] | — | Images for the frame; only the first is used, and children take priority |
frameLabel | string | "產品儀表板示意圖" (Product dashboard illustration) with the placeholder | Accessible name of the frame figure |
children | ReactNode | Placeholder dashboard | Frame content (screenshot or component); it provides its own semantics |
container | RefObject<HTMLElement> | — | Ref of the nested scroll container; omit to use the window as the scroll container |
className | string | — | Class merged into the root section |
BrowserFrameHeroAction
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Button text |
href | string | — | Renders an a link when provided, otherwise a type="button" |
onClick | () => void | — | Click callback |
BrowserFrameHeroImage
| Field | Type | Default | Description |
|---|---|---|---|
src | string | — | Image URL; omit it to draw the placeholder dashboard |
alt | string | — | Alt text, used as the frame's accessible name when frameLabel is not set |
How it works
- Scroll-driven:
useScrolltargets the section itself (offset: ["start end", "end start"]). Between progress 0 and 0.4,rotateXgoes fromtiltto 0,rotateYfrom-tilt × 2/3to 0,scalefrom 0.94 to 1 andyfrom 40px to 0, then holds the final state. - Smoothing: all four values pass through
useSpring(damping 24) with stiffness read from--wb-browser-frame-hero-stiffness(default120). The variable is read once on mount, so changing it at runtime needs a remount. - The outer wrapper sets
perspective: 1400px, and the frame rotates around its bottom center. - Entrance: eyebrow, title, subtitle and CTAs rise 16px and fade in one after another, 80ms apart; the frame fades in and rises 24px. Both use
--wb-browser-frame-hero-duration(default600ms) withcubic-bezier(0.22,1,0.36,1). - Accent:
--wb-browser-frame-hero-accent(default#0d9488in light,#2dd4bfin dark), used by the eyebrow, primary button, focus ring and the placeholder dashboard's highlighted figures. - From md up the layout is a 4 / 8 two-column grid; on narrow screens the frame moves below the title.
Accessibility
- The root is a
sectionwitharia-labelledbypointing at the title; the heading level comes fromas. - The frame is a
figure. The placeholder dashboard isaria-hiddenand thefiguregets its name fromaria-label. When you passchildren, your content provides the semantics; addframeLabelif it needs a name. - The three dots, the shadow under the frame and the laptop base are decorative and hidden from assistive tech.
- CTAs are
aortype="button"with a clear focus-visible ring. - With "reduce motion" turned on, the scroll-driven tilt and scale stay at the final state (facing forward, full size) and the entrance becomes a 150ms fade; the entrance media query applies from the first paint.
Particle Field Hero
A hero over an interactive particle field: particles drift and link up when close, the pointer pushes them away, and the headline stays legible on top.
Skyline Scroll Hero
A scroll-driven React hero with a segmented city skyline — as you scroll the sky shifts from dusk to night, buildings light their windows section by section, the stage headline switches, and the moon rises in the last stage.