damon-ui
Browse items
block

Page hero

The opening section of a marketing page: eyebrow, a big fluid title, intro, actions and optional media, with a short staggered rise-in. Sized by the text-hero / text-display tokens and coloured by the surface-* tokens.

npx shadcn add @damon/page-hero

Without the @damon alias: npx shadcn add https://damon-ui.pages.dev/r/page-hero.json · raw markdown

Preview

Kitchens

A kitchen made for the way you cook

We design, build and install in one team, so the person who measures is the person who fits.

Your photo here

Built to last

Kitchens, wardrobes and stairs made in Auckland.

Installs components/page-hero.tsx. Adds the surface-*, brand* and text-hero / text-display tokens to globals.css if missing (@damon/theme-marketing defines them all). Uses tw-animate-css, which shadcn projects already import.

When to use

  • The top of service, about, pricing and landing pages.
  • With a photo, illustration or a short form beside the copy (media).
  • On a dark section (tone="inverse") when the header sits over it.

When NOT to use

  • App pages. Use @damon/page-header.
  • Carousels or video heroes. Build those deliberately; this block stays simple.
  • More than one per page. It renders the page's h1.

Props

PropTypeDefaultNotes
titleReactNoderequiredRendered as the h1; labels the section.
introReactNodeTwo or three lines.
eyebrowReactNodeSmall uppercase label.
actionsReactNodeButtons/links.
mediaReactNodeBeside the copy on lg, below on mobile.
size"hero" | "display""hero"hero for 2–3 words; display for a sentence.
align"start" | "center""start"Ignored when media is set.
tone"surface" | "background" | "inverse""surface"bg-surface-1, bg-background, or dark bg-surface-inverse.
headingIdstringgenerated
className, …section propsAdd top padding if a fixed header overlaps (pt-40).

Minimal example

import { PageHero } from "@/components/page-hero"

<PageHero title="Built to last" intro="Kitchens, wardrobes and stairs made in Auckland from native timber." />

Real example

import Image from "next/image"
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { PageHero } from "@/components/page-hero"

<PageHero
  eyebrow="Kitchens"
  size="display"
  title="A kitchen made for the way you cook"
  intro="We design, build and install in one team, so the person who measures is the person who fits."
  actions={
    <>
      <Button size="lg" asChild><Link href="/contact">Book a free measure</Link></Button>
      <Button size="lg" variant="outline" asChild><Link href="/work">See our work</Link></Button>
    </>
  }
  media={
    <Image src="/kitchens/hero.jpg" alt="Rimu kitchen with brass handles" width={960} height={720} priority className="rounded-2xl" />
  }
  className="pt-32"
/>

Constraints

  • One per page: it owns the h1, and the section is aria-labelledby it.
  • The rise-in runs on load (not on scroll), under motion-safe: only. Content is visible without JS.
  • Title size comes from tokens: text-hero = clamp(2.5rem, 7vw, 6rem), text-display = clamp(2rem, 4.5vw, 3.5rem). Change them in the theme, not per page.
  • Server component (no client JS).

Files

  • blocks/page-hero.tsx