Hero blueprint
A hero on a dotted grid with dashed guides and dimension labels around a content slot.
npx shadcn@latest add https://ui.goodtabs.co/r/hero-blueprint.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/hero-blueprint
Design systems
Measure twice, ship once
Spacing, radii and type on one grid, so every screen lines up.
Eyebrow, title, one line and two actions on the grid.
With a live slot
Live preview
Every control, to the pixel
A real control group in the slot, framed by the guides.
Usage
import { HeroBlueprint } from "@/components/hero-blueprint"
import { Button } from "@/components/ui/button"
<HeroBlueprint
eyebrow="Design systems"
title="Measure twice, ship once"
actions={<Button>Read the spec</Button>}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| eyebrow | string | Small uppercase line above the title. | |
| title | ReactNode | The headline. | |
| description | ReactNode | One or two sentences under the title. | |
| actions | ReactNode | Buttons and links. | |
| children | ReactNode | The live slot below the actions: a demo, screenshot or control. |
Source
hero-blueprint/hero-blueprint.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
type HeroBlueprintProps = Omit<React.ComponentProps<"section">, "title"> & {
/** Small uppercase line above the title. */
eyebrow?: string;
/** The headline. Pass a string or your own element. */
title: React.ReactNode;
/** One or two sentences under the title. */
description?: React.ReactNode;
/** Buttons and links, usually one primary and one outline. */
actions?: React.ReactNode;
/** The live slot: a demo, a screenshot or an interactive element, below the actions. */
children?: React.ReactNode;
};
/** A dimension line: ticks at both ends, a hairline between and a mono label in the middle. */
function Dimension({ label }: { label: string }) {
return (
<div aria-hidden="true" className="flex items-center font-mono text-[10px] text-muted-foreground">
<span className="h-2 w-px bg-border" />
<span className="h-px flex-1 bg-border" />
<span className="px-2 leading-none">{label}</span>
<span className="h-px flex-1 bg-border" />
<span className="h-2 w-px bg-border" />
</div>
);
}
/**
* A hero drawn like a technical sheet: a dotted grid, dashed guides at the content edges and dimension labels.
* Static server component. The content sits in front, so the drawing never carries information.
*/
function HeroBlueprint({ eyebrow, title, description, actions, children, className, ...props }: HeroBlueprintProps) {
return (
<section
data-slot="hero-blueprint"
className={cn(
"relative isolate overflow-hidden bg-background bg-[radial-gradient(var(--border)_1px,transparent_1px)] bg-size-[16px_16px] py-16 sm:py-20",
className,
)}
{...props}
>
<span
aria-hidden="true"
className="absolute inset-x-0 top-16 -z-10 border-t border-dashed border-border sm:top-20"
/>
<span
aria-hidden="true"
className="absolute inset-x-0 bottom-16 -z-10 border-b border-dashed border-border sm:bottom-20"
/>
<div className="relative mx-auto w-full max-w-3xl px-4">
<div className="absolute inset-y-0 left-4 w-px border-l border-dashed border-border" aria-hidden="true" />
<div className="absolute inset-y-0 right-4 w-px border-r border-dashed border-border" aria-hidden="true" />
<div className="absolute inset-x-4 -top-9 sm:-top-11">
<Dimension label="max 768" />
</div>
<div className="relative flex flex-col items-center gap-4 bg-background px-4 py-10 text-center sm:px-10 sm:py-14">
{eyebrow && <p className="m-0 font-mono text-xs tracking-wide text-muted-foreground uppercase">{eyebrow}</p>}
<h1 className="m-0 max-w-2xl text-3xl leading-none font-medium tracking-tight text-balance sm:text-5xl">
{title}
</h1>
{description && <p className="m-0 max-w-xl text-sm text-muted-foreground sm:text-base">{description}</p>}
{actions && <div className="flex flex-wrap justify-center gap-2">{actions}</div>}
{children && <div className="mt-4 w-full">{children}</div>}
</div>
<span
aria-hidden="true"
className="absolute right-6 -bottom-9 font-mono text-[10px] text-muted-foreground sm:-bottom-11"
>
16 px grid
</span>
</div>
</section>
);
}
export { HeroBlueprint };
For AI agents
Hand your agent this page, the markdown at /components/hero-blueprint/prompt.md, or the Copy AI prompt button above.
When to use
- A landing page for a design system, a token set or a tool for builders
- When the product is about precision and a drawn grid backs that up
- With a live slot to show the real thing inside the guides
When not to use
- Consumer or editorial pages, where the technical drawing feels cold
- More than once on a page, or inside app screens
- Over a photo or a busy background, which hides the dots
Agent notes
- Static server component with no motion; the grid, guides and labels are aria-hidden decoration
- The content block has a background, so the dots stop at its edge and text keeps its contrast
- The labels are fixed text (max 768, 16 px grid) that match max-w-3xl and the 16px dot spacing; edit them if you change either
- Guides sit at the section's vertical padding, so className overrides of py-* should move top and bottom offsets too
The maths
- Dots repeat every 16px, which is 4 × the 4px unit, so every spacing token lands on a dot.
- The content box is max-w-3xl = 48 × 16 = 768px, and the dimension line is labelled with that number.
- Guides sit at top-16 and bottom-16, 64px or 4 grid cells in, with the same offset on both sides so the frame is symmetric.