Split hero
Headline and supporting copy beside an image. The default page opener.
Installation
npx shadcn@latest add http://localhost:3000/r/hero-split.jsonMKT UI is not published yet, so this points at your local development server. Set NEXT_PUBLIC_REGISTRY_URL to the deployed origin to show the public command.
Also installs: container, section, cta-group, media-frame.
Usage
import { Button } from "@/components/ui/button";
import { HeroSplit } from "@/components/hero-split";
<HeroSplit
eyebrow="Licensed & insured"
title="Plumbing problems fixed properly, the first time."
description="Same-day emergency slots across north Austin, upfront pricing, and a six-year workmanship warranty."
actions={
<>
<Button asChild>
<a href="#quote">Request a quote</a>
</Button>
<Button variant="outline" asChild>
<a href="tel:+15125550142">Call (512) 555-0142</a>
</Button>
</>
}
note="Free quotes · No call-out fee on scheduled work"
image={{ src: "/hero.jpg", alt: "Technician fitting a copper pipe" }}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title (required) | ReactNode | — | The headline. Rendered as the page's h1 — use this section once per page. |
| eyebrow | ReactNode | — | Short label above the headline. Good for a credential or category, not a second sentence. |
| description | ReactNode | — | One or two sentences on what you do and who for. |
| actions | ReactNode | — | Buttons or links. Put the action you most want taken first — it is also the first tab stop. |
| note | ReactNode | — | Reassurance under the actions, e.g. "Free quote · No obligation". |
| proof | ReactNode | — | Proof below the actions — a rating, a logo strip, a credential row. |
| image | { src, alt, caption? } | — | Convenience image. Ignored when `media` is supplied. |
| media | ReactNode | — | Render your own media instead: a next/image with fill, a video, a screenshot frame. |
| reverse | boolean | false | Put the media on the left on wide screens. DOM order does not change. |
| surface | "default" | "muted" | "brand" | "inverted" | "default" | Background treatment. |
Behavior
Copy always comes first in the DOM. reverse moves the image visually with CSS
order, but the markup order never changes. On a phone the visitor reaches the
headline and call to action without scrolling past a large image, and keyboard and
screen-reader users get the same sequence.
The hero image loads eagerly. It is above the fold, so the built-in MediaFrame
uses loading="eager" and fetchPriority="high". If you pass your own media, set
those yourself — a lazy-loaded hero image is a Largest Contentful Paint problem.
Space is reserved before the image loads. The frame has a fixed aspect ratio, so the page does not jump when the image arrives.
Using next/image
The section stays framework-neutral, but nothing stops you passing an optimized image:
import Image from "next/image";
<HeroSplit
title="…"
media={
<MediaFrame aspect="square">
<Image src={heroImage} alt="…" fill priority className="object-cover" />
</MediaFrame>
}
/>Limitations
- No built-in background-image or video variant. Those are separate sections
(
hero-background,hero-video) and are not implemented yet. proofis an open slot rather than a structured prop. A dedicated rating and logo strip component is planned.- The two-column split becomes one column below
lg(1024px). There is no option for a three-column hero.
Related
- Composition — where a hero sits in a page
- Theming — surfaces and the type scale