Hero

A centered marketing hero section. Named parts you assemble: an announcement eyebrow, a balanced headline, a subtitle, a CTA row, a check-circle feature list and an integrated social-proof row.

Update availableKoala UI v11 is here!

A Design System built for AI-Powered Products

A Design System for builders of AI assistants, copilots and intelligent tools, ship MVPs fast.

  • Light/Dark/Moonlight themes at 1 click
  • +3,200 Components
  • New updates every month
  • Consistent responsive
LCKPDB
+620 Designers have joined already
5.0 Ratings

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add hero

Usage#

usage.tsxTSX
import { Button } from "@/components/ui/button"import {  Hero, HeroContent, HeroTitle, HeroSubtitle, HeroActions, HeroFeatures, HeroFeature,} from "@/components/ui/hero"export function Example() {  return (    <Hero>      <HeroContent>        <HeroTitle>Ship the product, not the plumbing</HeroTitle>        <HeroSubtitle>          Everything your team needs to go from idea to launch, in one workspace.        </HeroSubtitle>        <HeroActions>          <Button size="lg">Start free</Button>          <Button size="lg" variant="outline">Book a demo</Button>        </HeroActions>        <HeroFeatures>          <HeroFeature>No credit card</HeroFeature>          <HeroFeature>Cancel anytime</HeroFeature>        </HeroFeatures>      </HeroContent>    </Hero>  )}

Minimal#

Drop the features and social-proof rows for a lean hero: just the eyebrow, title, subtitle, and CTAs. Override the vertical rhythm on HeroContent when you want it tighter.

New: Koala UI for React

Build polished products, faster

A production-ready component library you can install with one command and own forever.

Display title#

size on HeroTitle sets the headline's scale. The default "lg" peaks at 60px, level with a SectionHeader size="lg"; "xl" is the display cut for the page's one big statement, peaking at 72px. The tracking stays tight: DM Sans follows its optical-size axis, so at display sizes it already sets in its tighter cut. Widen the column with max-w-5xl on HeroContent so a display headline keeps two lines, and give the rating size="md" stars so the proof row holds its own under the bigger type.

Update availableKoala UI v11 is here!

A Design System built for AI-Powered Products

A Design System for builders of AI assistants, copilots and intelligent tools, ship MVPs fast.

LMCGKSPKDKBP
5.0 Ratings

Rotating highlight#

Pass rotate a list of phrases to HeroHighlight and the wash becomes a rotating zone: the words inside swap, each entering with a per-character stagger while the previous one clears, the wash hugs each word (tweening its width as the phrase changes), and each phrase takes the next color in the palette (semantic DS roles, so it tracks every theme), the tint crossfading as it swaps. Lead every phrase with the same word so the left edge stays anchored against the copy beside it and only the right edge resizes. Give the title a touch more line-height (the demo uses leading-[1.2]) so the wash always clears the line above it. It holds each phrase for interval ms (default 2600) and honors prefers-reduced-motion by holding the first phrase with no cascade.

Koala UI v1.0 is here

Bring your product into

The highlight wash hugs each word, resizing as it rotates, paints each phrase in its own color, and the letters arrive with a per-character stagger, so the headline stays alive on its own.

Cursors#

Add a HeroCursors layer and place HeroCursors in it for the feel of a live, shared design file. Each cursor wanders its own slow loop, pauses twice, and clicks at each pause: the arrow presses and a soft ripple leaves the tip. Give every cursor a different duration (seconds per loop, default 16) and phase (0 to 1) so they never move in step. color takes a semantic role (brand, purple, teal, pink, orange, success), so the fills follow every theme, and facing points the arrow left or right; the name tag always hangs on the side away from the point. Place each cursor's tip with className, and resize its loop with [--cursor-x:…] / [--cursor-y:…] (a negative x mirrors it).

Pass labels (an array of names) instead of children and the name tag rolls to the next one on every click, twice a loop: the old name lifts out, the new one rises in, and the pill eases to its width, the same AnimatedLabel roll every changing label in Koala uses. The swap is timed off the cursor's own loop, so it always lands as the arrow presses, and it stops whenever the cursor is hidden.

The layer is decoration only. It is hidden from assistive tech, lets every click through to the copy underneath, and shows its cursors only when the hero itself is at least 64rem wide (a container query, so it reads the hero's width, not the window's), which keeps them in the gutters and off the headline on smaller frames. When your cursors roam space the copy never reaches (the bands above and below it, as in this demo), reveal them sooner with className="@2xl:block" (a 42rem hero). Under prefers-reduced-motion they hold still where you placed them, with no ripple.

Built together

Where your whole team designs in one place

Clients, developers and designers working in the same file, each cursor on its own path.

Poster wall#

When the product itself is a wall of covers (events, classes, listings, releases), open on that content instead of a screenshot of it. A HeroScatter layer fills the band with tilted HeroScatterTile prints and the copy stands in the clearing at its centre. Each tile takes a size (sm / md / lg, square, stepping up twice as the hero widens), a depth (far sits it smaller and lighter, further back), a tilt in degrees, and a delay, so the wall assembles card by card on mount. Place each one with className; a negative offset (-left-4) lets the band crop it, which is what makes the wall read as bigger than the page.

Give the copy a taller pt / pb than usual: that clearing is what keeps the top and bottom cards off the words where there are no gutters to put them in. The layer is a size container, so hold the rest back until the hero has earned the room (hidden @5xl:block for the sides of a 48rem copy column). Like the cursors it is decoration only: hidden from assistive tech, never in the way of a click, and still under prefers-reduced-motion. The copy on top of it stays the house stack, and the headline goes plain: the wall is already the colour on this band, and a HeroHighlight wash under a 72px line reads as a slab rather than an accent.

Free to host

Host the kind of night people talk about

Supper clubs, workshops, launch parties, a five-a-side game: build the page, send the invite, and keep every RSVP in one place.

Feature columns#

HeroFeatures has a second shape. Set layout="columns" and the inline check row becomes three capability columns, each a bare brand-tinted mark over a title and a sentence: pass icon and title to every HeroFeature inside and the sentence stays as its children. Reach for it when the three claims each deserve a sentence rather than three words, and the page has no room for a separate feature section above the fold.

Nothing is drawn between the columns: no rule, no padding, no surface, so the gutter carries the separation and stays wide enough to do it. It is a grid, not a wrapping row, and every column subgrids onto the same three tracks, so a title that wraps to two lines pushes all three sentences down together instead of stranding its neighbours half a line high. Below the sm breakpoint the tracks collapse and the columns stack. The row follows the hero it sits in: centered under a centered column, flush-left in a split, and white over background media.

Design to launch

Design, build and launch in one place

Eighty-nine components, four themes and whole page sections, wired together so the site you sketch on Monday is live on Friday.

  • Make it yours

    Four themes and a radius knob, so the kit wears your brand before you write a line.

  • Build from finished parts

    Whole page sections, not just buttons: paste a hero, a pricing table, a footer.

  • Ship the same day

    You own the source. Drop it in your repo and launch without waiting on a handoff.

A careers page and an FAQ page built with Koala UI, side by side in two browser windows

Split layout#

Set layout="split" on Hero to turn the content into a two-column grid: a HeroColumn of copy beside a HeroMedia visual (an image, screenshot, or logo wall). It folds back to a single stacked column below the lg breakpoint. The same parts read the layout from context, so the only change is the prop.

Now in public beta

Analytics your whole team actually uses

Real-time dashboards with no setup. Connect a source and watch the numbers land in seconds, on every device.

APTM
Loved by 2,000+ teams

Background media#

Set layout="background" and add a HeroBackground to turn the hero into a full-bleed band: the media covers the section, a gradient scrim lays over it, the copy flips to white, and the eyebrow goes glassy, all from the one prop. Drop a plain <img> in for a photo, or an autoPlay muted loop playsInline <video> for ambient motion (muted autoplay is the only kind browsers allow unprompted). Give the video a poster so the band never flashes empty, and a still <img className="hidden motion-reduce:block"> fallback so it holds a frame under prefers-reduced-motion.

Now in private beta

Support that never sleeps

AI agents pick up every call, answer in seconds, and hand off to your team only when it matters.

Series A: $61M to scale support

AI that talks like a human. Handles millions of calls.

AI agents for enterprise support.

ApexHelioDewnCobaltBlossom

Scroll stage#

HeroStage is the hero that plays itself as the reader scrolls: one photograph opens full-bleed under a display line, contracts into a centred card, and a collage assembles around it while the copy rises underneath. Several things move at once rather than one: the frame contracts, the picture inside it pushes in on its own slower beat (so the shot gains depth instead of just getting smaller), the display line grows past the frame and defocuses as the camera goes through it, and each collage piece flies in from its own edge, leaning, and settles level. Once landed, the pictures keep a slow drift inside their frames, each on its own clock, so the composition breathes instead of freezing when the reader stops. All of it is scrubbed by the scroll position through a single CSS view timeline, so there is no animation library, no scroll listener and no requestAnimationFrame loop anywhere in it: it runs backwards when the reader scrolls back up, and costs nothing off screen. Compose it in place of HeroContent. Every part is droppable, so a stage holding nothing but a HeroStageMedia is a picture that contracts.

It spends three viewports of scrolling on a single statement, so it is a page's one cinematic moment, not a section to reach for twice. Browsers with no scroll-driven animations, and readers who asked for reduced motion, get a single viewport holding the last frame: the picture at its card size, the collage assembled around it, and the eyebrow, lede and CTAs where they land. Only the display word is missing there, since a word cut to fill a screen cannot sit inside a card, so put an ordinary HeroTitle in the closing HeroStageReveal when the section needs a headline visible at rest. See the scroll stage section for the finished slab.

Parallax cover#

layout="cover" is the editorial opener: one picture or clip takes the whole viewport (100svh, so a phone's shrinking browser chrome can never cut the words off) and the copy stands along its bottom edge, the headline in one corner and the paragraph in the other. Where layout="background" centres a copy column in the middle of the band and treats the media as a backdrop for it, here the media is the statement and the words are a caption laid along the foot of it, so the frame is never covered. Set the headline to size="2xl", the 96px poster cut, and keep it to two or three words.

It does not stay full bleed. As the reader scrolls, the frame pulls in to the page's own container (90rem, the max-w-8xl every other section sits in) and rounds its corners, so the opening picture hands the page back to its grid instead of ending at a hard seam. One registered number, --hero-cover-t, animates on the band and the frame's width, its corner and the caption's padding are calc()s reading it, so they cannot drift out of step: the caption steps in by exactly what the frame pulls in by and the words hold the same distance from the picture's edge from the first frame to the last, at every width. Retune the landing with [--hero-cover-gutter:…], [--hero-cover-max:…] and [--hero-cover-radius:…], and when it runs with [--hero-cover-contract-start:…] / -end (a hero opens at the top of the page, which is already halfway through its own cover range, so the beat starts at 50% and finishes half a viewport of scrolling later).

The parallax is one prop: <HeroBackground parallax>. The media travels slower than the band it fills while the caption over it travels a little faster, so the two planes separate and the band reads as a window rather than a picture glued to the page. It is scrubbed by the scroll position through a CSS view timeline, the same engine the scroll stage runs on, so there is no animation library (parallax is the effect people install GSAP and Lenis for), no scroll listener and no requestAnimationFrame loop: it runs on the compositor, off the main thread, goes backwards when the reader scrolls back up, and costs nothing off screen. The media is held a quarter larger than its frame for the whole travel, which is the slack the drift moves within, so give it a picture with room around its subject. Retune with [--hero-parallax-travel:…] and [--hero-parallax-zoom:…] on the hero, keeping travel at or under (zoom - 1) / 2 or the frame will show its ground at the ends of the drift.

Browsers with no scroll-driven animations, and readers who asked for reduced motion, get the same hero full bleed and still, with the media sitting level in its frame: a parallax has a neutral frame, and the neutral frame is a finished, full-bleed cover. The drift also works under layout="background", which declares the same timeline. See the parallax cover section for the finished slab.

API reference#

Hero · HeroContent · HeroColumn

Hero is the full-bleed <section> that provides the styling context. It takes a layout prop: "centered" (default), "split", "background", or "cover" (a full-viewport picture with the copy standing along its bottom edge). HeroContent is the max-width column (a stacked column when centered, a two-column grid when split); HeroColumn groups the copy in the split layout. All forward their native element props.

HeroTitle · HeroHighlight · HeroSubtitle

The balanced <h1> (its size is "lg", 60px, the "xl" 72px display cut, or the "2xl" 96px poster cut for a cover), HeroHighlight to mark a keyword inside the title with a soft brand wash, and the muted lead paragraph. HeroHighlight also takes rotate (a list of phrases to cycle through, with a per-character stagger, a wash that hugs each word, and a color per phrase) and interval (ms each phrase holds, default 2600). The wash is the only way Koala marks a word in a headline: no gradient text anywhere in the system. The announcement pill above the title is not a Hero part: it is the standalone Announcement atom, so the same pill works in a navbar or a pricing header. Over media it takes variant="glass".

HeroActions

The centered CTA row. Compose our Buttons inside it.

HeroFeatures · HeroFeature

HeroFeatures wraps the checklist; HeroFeature is one item and renders its own green check-circle glyph before the label. HeroFeatures also takes balance, which caps the row at a 36rem measure so the items wrap into even rows (2 + 2) instead of stranding the last one alone on its own line (3 + 1): text-wrap: balance, but for a flex row. Worth setting on any list of four or more items; a list that already fits the measure is untouched. Pass layout="columns" instead and the row becomes capability columns: each HeroFeature then takes an icon, drawn bare in the brand accent, and a title above the sentence, and drops the check-circle. Give every item in that row an icon, or none of them one: the columns share their tracks, so a single missing mark shifts that column's copy up a row.

HeroSocialProof · HeroRating

The proof row. Drop an AvatarGroup in for the overlapping stack and a star rating beside it. HeroRating takes a value and max (both default 5), a star size (default "sm"; "md" beside a larger avatar stack), and renders the label as children.

HeroMedia

The visual region. In a split hero it fills the second column; in a centered hero it sits below the copy. Drop an image or screenshot in, or a wall of customer logos. The demos ship an image placeholder so you can drop your own screenshot straight in.

HeroBackground

The full-bleed media layer for layout="background" and layout="cover". It stretches its child <img> or <video> to cover the section and lays a gradient scrim over it, so the white copy stays legible on any photo. It sits behind HeroContent, and the section's overflow-clip (plus any rounded corners) clips the media to the band, which is also what contains the parallax travel. It takes parallax, which drifts the media against the page as the reader scrolls (a CSS view timeline, no animation library and no scroll listener; still under reduced motion). See Parallax cover above.

HeroCursors · HeroCursor

HeroCursors is the decorative layer: it covers the hero, is aria-hidden and pointer-events-none, and shows its cursors once the hero is at least 64rem wide. HeroCursor is one cursor, positioned by its tip through className. It takes color (default "brand"), facing ("left" or "right", default left), duration (seconds per loop, default 16) and phase (0 to 1, default 0). Its children are the name tag; omit them for a bare arrow, or pass labels (a string array) for a tag that rolls to the next name on each click.

HeroScatter · HeroScatterTile

HeroScatter is the poster-wall layer: like HeroCursors it covers the hero, is aria-hidden and pointer-events-none, and is a size container, but it sits behind the copy rather than over it. HeroScatterTile is one card: a photo print placed by its className (-left-4 top-4, plus a hidden @5xl:block gate where it needs room), holding a plain <img> that it sizes, rounds and crops. It takes size ("sm", "md" default, or "lg"; square, and each steps up twice as the hero widens), depth ("near" default or "far", which steps the card back into the page), tilt (degrees, keep the wall between about -12 and 12) and delay (ms before it drifts in, so the wall assembles card by card). It holds still under prefers-reduced-motion.

HeroSpread · HeroSpreadMedia · HeroSpreadPanel · HeroSpreadIndex

The magazine spread: compose these instead of HeroContent, since the panel pads itself. HeroSpread is the two-track grid (stacked below lg); HeroSpreadMedia is the picture half, which covers and crops a plain <img> or <video> and carries its own aspect ratio while the halves are stacked; HeroSpreadPanel is the inked half, which takes tone ("brand" default, the raw accent, or "ink", a slab pinned dark on every page theme) and wants exactly two children: it pushes the first to its top edge and the second to its foot. HeroSpreadIndex is the chapter mark in the outer corner, decorative and hidden from assistive tech. Over brand the lead action is <Button tone="onMedia">; over ink it is variant="neutral".

HeroStatement · HeroSignoff

HeroStatement is the section's <h1> when the hero is a sentence, so it replaces HeroTitle rather than joining it: display scale on a 36-character measure, semibold at 1.2 leading because a long sentence in bold display type reads as shouting. Mark the phrase it turns on with HeroHighlight, exactly as in a headline. HeroSignoff is the letter's closing under it, one line per child, in the house's small monospace voice. To close it by hand instead of with a typed name, drop a Signature in as its last line: it writes itself in once the hero is on screen.

HeroMosaic · HeroFrame

HeroFrame is one framed picture anywhere in a hero: the unpinned sibling of a HeroScatterTile (that one is a print pinned into a wall; this one sits in normal flow). Give it its shape with className (aspect-square, a max-w-*) and a plain <img> inside; it crops it, keeps the hairline on top of the picture and drifts in after delay ms, holding still under prefers-reduced-motion. tone="mono" drops its colour, which is what makes a wall of unrelated photographs read as one picture. HeroMosaic is the band those frames sit in: a twelve-track grid across the top of the hero (two tracks while stacked), so a tile can take a third or a sixth of the row, break the top line with its own mt-*, and step out of a narrow band with a hidden lg:block gate. The gates are viewport breakpoints, not container queries, because the tracks are declared on the element that would have to be the container and nothing can answer its own container query; inside a docs frame that still measures the frame, which is an iframe of its own. Pull the band up past the hero's top edge with a negative -mt-* and the section opens on pictures the band has already cropped.

HeroStage · HeroStageMedia · HeroStageTitle · HeroStageCard · HeroStageReveal

The scroll stage: compose these instead of HeroContent, not inside it. HeroStage is a scroll track taller than the viewport with one pinned screen inside it, and the only thing that declares the timeline. HeroStageMedia is the frame that contracts from full-bleed to a card (give it a plain <img> or a muted, looping <video>; it covers rather than fits, so the crop tightens as it closes) and takes scrim (default true), the gradient that carries the word. HeroStageTitle is the section's <h1> at poster scale, set inside the frame so the frame's own clip trims it: keep it to two or three words. Given a plain string it leaves character by character: the line grows past the frame and lifts as one object, while each letter sits in a mask of its own and slides up out of it a beat after the one before it, so the letterform stays crisp right up to the edge that cuts it instead of spending its exit as a grey smear. The split row is hidden from assistive tech with the heading carrying the text as its label, so a screen reader still reads a word rather than a column of letters. Retune the cascade with [--hero-stage-exit-stagger:…] (0 turns it off) and how far a letter travels with [--hero-stage-letter-travel:…]. That travel overshoots one box-height on purpose: a glyph's ink is not bounded by its line box, so a descender hangs below it and a letter moved exactly its own height leaves its tail behind the edge. Raise it for a face with deep descenders. Pass anything that is not a plain string and the whole line leaves together. HeroStageCard is one collage piece and HeroStageReveal a band of late copy; both take an index, their place in the stagger; HeroStageCard also derives its picture's drift direction and duration from that index, so neighbours never sway in step. Tune a part's arrival with [--hero-stage-drift:…] (sideways, negative arrives from the left), [--hero-stage-shift:…] (vertical, negative drops in from above) and [--hero-stage-tilt:…] (the lean it settles out of). Size the card the picture lands on with [--hero-stage-w:…] / [--hero-stage-h:…] on the stage, its corner with [--hero-stage-radius:…], the total scroll length with [--hero-stage-track:…] (default 280svh) and the gap between stagger steps with [--hero-stage-stagger:…].

Place everything on the stage with inset utilities (top-*, left-*, inset-x-0), never translate-* or scale-*: Tailwind v4 writes those to the standalone translate and scale properties, which are the two the entrance animates, so a centring -translate-x-1/2 would be overwritten and the part would slide sideways as it arrived. The parts centre themselves.

FAQ#

Hero is pure layout, so it ships no controls of its own. It is composed entirely of existing Koala components: drop our Button inside `HeroActions`, an `AvatarGroup` and `Rating` in `HeroSocialProof`, and a dot `Badge` for the eyebrow, so the hero stays consistent with the rest of the design system.