Blur-In Headline Hero
A minimal centred React hero where the headline rises character by character out of a blur and the single call-to-action breathes with a slow halo while everything else stays still; Chinese splits per character, English keeps words intact, and every timing is a CSS variable.
A hero with generous whitespace, everything centred: eyebrow (accent dot + text) → large headline → subtitle → one pill-shaped primary button plus an optional plain-text secondary link. Only two things move. The headline rises grapheme by grapheme out of a blur, and 150ms after it finishes the subtitle and button fade in; from then on the primary button breathes with a slow scale and outer halo. Hovering stops the breathing and instead lifts the button slightly and nudges the arrow 2px to the right. The background is a flat colour with no decoration, with an optional 48px hairline above the headline.
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 blur-in-headline-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.
<BlurInHeadlineHero/>
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/blur-in-headline-hero.en.jsonOr, once registries are configured in components.json, install it as @webberui/blur-in-headline-hero.
Usage
import { BlurInHeadlineHero } from "@/components/ui/blur-in-headline-hero";
<BlurInHeadlineHero
eyebrow="Stillwater Notes | New release"
title="Turn off the noise. Keep the one line you came to write."
subtitle="A writing space that stays out of your way: no notifications, no sidebars."
primaryAction={{ label: "Start writing free", href: "/signup" }}
secondaryAction={{ label: "See how it works", href: "#how" }}
/>To change the pacing or accent, override the CSS variables:
<div
style={{
"--wb-blur-in-headline-hero-accent": "#7c3aed",
"--wb-blur-in-headline-hero-stagger": "45ms",
"--wb-blur-in-headline-hero-breath": "3.2s",
} as React.CSSProperties}
>
<BlurInHeadlineHero title="Slower is fine, too" primaryAction={{ label: "Begin" }} />
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Headline (required); a string animates glyph by glyph, a ReactNode fades and rises as one block |
eyebrow | ReactNode | — | Small eyebrow above the headline, preceded by an accent dot |
subtitle | ReactNode | — | Subtitle |
primaryAction | BlurInHeadlineHeroAction | — | The single primary CTA (pill-shaped, with a breathing halo) |
secondaryAction | BlurInHeadlineHeroAction | — | Secondary plain-text link |
as | "h1" | "h2" | "h1" | Heading level used for the headline |
minHeight | number | 560 | Minimum section height (px) |
splitBy | "char" | "word" | "char" | Split unit: char (each character / letter) or word (each word; Chinese is grouped into phrases at punctuation) |
breathing | boolean | true | Whether the CTA keeps breathing (scale + outer halo) |
showRule | boolean | false | Show a 48px hairline above the headline |
onEntered | () => void | — | Called once every block has entered (also fires under reduced motion) |
className | string | — | Merged into the root section |
BlurInHeadlineHeroAction
| Field | Type | Default | Description |
|---|---|---|---|
label | string | — | Button text |
href | string | — | Link target; renders an a when provided |
onClick | () => void | — | Click handler; without href a type="button" button is rendered |
CSS variables
| Variable | Default | Description |
|---|---|---|
--wb-blur-in-headline-hero-accent | #0d9488 (dark #2dd4bf) | Eyebrow dot, primary button fill and breathing halo |
--wb-blur-in-headline-hero-stagger | 30ms | Delay between headline glyphs |
--wb-blur-in-headline-hero-duration | 600ms | Entrance duration of each glyph and block |
--wb-blur-in-headline-hero-breath | 2.4s | Length of one CTA breath |
How it works
- Splitting: the headline is split into graphemes with
Intl.Segmenter(falling back toArray.from), so combined characters and emoji stay whole. Word granularity is deliberately avoided — it depends on ICU dictionaries, and server and browser can split differently, breaking hydration. - Line breaking: each English word is wrapped in an
inline-block+nowrapgroup so per-letter animation never splits a word mid-way; each Chinese character stands alone and wraps normally. Closing marks such as 「,。」」 stick to the previous character and opening marks such as 「「(」 to the next, so they never start or end a line. - Each glyph enters with y
0.4em→ 0, opacity 0 → 1 andblur(6px)→ 0, delayed bystagger × step. Inwordmode an English word or a Chinese phrase shares one step and rises together. - The subtitle and button delays are computed with CSS
calc()from the headline's step count,--wb-blur-in-headline-hero-staggerand--wb-blur-in-headline-hero-duration, so they still enter 150ms after the headline when you change the variables. - Breathing starts only after the button has entered, and pauses on hover or keyboard focus so it never fights the focus ring's shadow.
Accessibility
- The root is a
sectionwitharia-labelledbypointing at the headline (generated withuseId) - The split headline carries an
aria-labelwith the full text and every glyphspanisaria-hidden, so screen readers announce the sentence once - The primary button is an
awhen it hashrefand atype="button"button otherwise, both with afocus-visiblering; the arrow icon is hidden from assistive tech - When the user's system asks to reduce motion, the breathing loop stops entirely and everything fades in over 150ms without movement or blur
Integration Hub Hero
A grid of integration icons surrounds a central product icon while beams flow along the connectors towards the centre in turn; hovering a service lights up its own connector.
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.