Start here

Arrows to move, enter to open, escape to close.

Ship/Now

Design · 4 min

Components

Fifteen blocks to copy, a handful of components that hold behaviour, and no configurable library.

Two kinds of thing live in src/components. Blocks are whole page sections you copy and edit. Components are the few small pieces that hold behaviour rather than styles, and those you import.

Neither is a configurable library. There is no variant prop and no theme object, because the moment a block takes six props to look right, editing the file would have been faster.

The blocks

Fifteen of them, in src/components/blocks. Open /blocks in your own app to see every one rendered with sample content, find the closest, copy the file into your page and change it. They read from the same design tokens as everything else, so they arrive in your colours.

BlockFor
HeroThe first screen: eyebrow, title, two actions
LogoCloudThe row of names under the hero
FeatureGridThree to six things your product does
StepsA numbered how-it-works
StatsFour numbers worth stating
PricingPlan cards, one highlighted
FaqNative <details>, so it works before hydration
TestimonialsQuotes with an attribution
CtaThe closing ask
FooterLink columns and the small print
BannerA dismissible strip, remembered in local storage
EmptyStateThe first screen of a table with no rows
DataTableA table on desktop, cards on a phone
SettingsFormA form with per-field errors and a pending state
PaginationPrevious and next, as links, so a page is a URL

The components

Eleven of them, and most exist because they hold behaviour, not because they hold styles.

The two you will reuse

ui/Card is the panel shape: border on a raised surface, consistent padding, optional title and lead. Everything in the dashboard is one.

<Card title="Billing" lead="Your purchases and the keys they issued.">
  <Receipts rows={orders} />
</Card>

ui/Field is a labelled input with its hint and error in the right place and the label actually associated with the control, which is the part people skip.

<Field label="GitHub username" note="Invitations go to this account.">
  <input name="github_login" />
</Field>

The ones that hold behaviour

ComponentWhat it knows
SignInFormThe magic link round trip and its three states
SignOutButtonRefresh before push, so the server sees the cleared cookie
LocaleSwitcherWrites the cookie the server reads on the next render
CopyFieldClipboard, plus the confirmation the click is meant to give
Logo, IconsLine-work SVG, sized in em so they follow the text

Why not more

A boilerplate that ships two hundred components ships two hundred opinions you have to override. The ones here are the ones that would otherwise be copy-pasted with a bug in the third copy.

When you need a real primitive, a dialog with a focus trap, a combobox, a date picker, install Radix or Base UI and style it with your tokens. Do not write your own dialog. Accessible focus management is genuinely hard and entirely solved.

Adding one

Server component by default. Add "use client" only when you need state, an effect or an event handler, and push it as far down the tree as it will go: a client component makes everything it renders client too.

Something wrong or missing on this page? Tell us.