UI.MD

Lockup

A centered stack of icon, heading, description, and actions that stands in for missing content.

Installation

$
npx shadcn@latest add https://ui.mattdowney.com/r/lockup.json

Usage

import {
  Lockup, LockupMedia, LockupEyebrow, LockupTitle, LockupDescription, LockupActions,
} from "@/components/ui/lockup"

Examples

Default

The empty state: an icon, what happened, and a way forward. Always give it LockupActions; without one the message is a dead end.

No matching invoices

Nothing came back for that search in the last 90 days. Try a shorter phrase, or widen the date range.

Eyebrow

The kicker that names a section, above the title. The caps, tracking, weight, and size all live in the component, so nothing is set at the call site. It is muted by default; pass className="text-accent" for the marketing treatment. It adds no gap of its own.

Why super templates?

Everything your team needs to ship a page, already decided

Layout, type, and spacing come pre-resolved, so the only thing left to choose is the words.

Sizes

One message at all five sizes. Only the media, type, and gaps change; the parts and their order never do. section and page both head real content rather than standing in for missing content, so neither pads itself.

Your inbox is clear

Nothing needs your attention right now.

Your inbox is clear

Nothing needs your attention right now.

Your inbox is clear

Nothing needs your attention right now.

Your inbox is clear

Nothing needs your attention right now.

Your inbox is clear

Nothing needs your attention right now.

Alignment

The same lockup inside a card, left-aligned and centered. Left reads better when the card is narrow enough that centered text leaves ragged edges on both sides. align defaults to center, so the second card passes nothing.

No shared files

Files people share with you land here.

No shared files

Files people share with you land here.

Tones

Tone tints the media chip and its glyph. It never changes the box, the type, or the layout.

Nothing here yet

Neutral reads as a resting state, not a problem.

No results

Accent is the default: an ordinary, expected outcome.

Import finished

Success confirms work that just completed.

Connection lost

Destructive is for a failure the reader has to act on.

Full page

The lg size, sized for a route that has nothing else on it. Set level={1} so the message is the page's heading, and step the buttons up to size="lg" to match the display-size title.

The run failed

The run was stopped, usually because the dev server restarted. Your transcript is saved.

API Reference

PropTypeDefaultDescription
sizeLockup"sm" | "md" | "section" | "page" | "lg""md"Scales the media, type, gaps, and the description's width cap. Every part reads this off the root, so you set it once. section is for heading a page section; page is a page's own headline sharing the viewport with other content; lg is a full, empty page.
alignLockup"center" | "start""center"start left-aligns the text and the action row. Uses logical alignment, so it flips under RTL.
toneLockupMedia"neutral" | "accent" | "success" | "destructive""accent"Colors the glyph, and the chip behind it when variant is tinted. Nothing else changes.
variantLockupMedia"tinted" | "bare""tinted"bare drops the chip and steps the glyph up one size, since an icon with nothing behind it needs more size to hold the same weight. Use it in tight containers, or when the media is an avatar or an image.
levelLockupTitle1 | 2 | 3 | 4 | 5 | 62Heading rank. A full-page lockup is usually the page's h1; one inside a card is usually an h3.
classNameLockupEyebrowstring-The kicker above the title, and the system's one sanctioned uppercase surface in page content. Muted by default so it stays subordinate to the title; pass text-accent for the marketing treatment. Sized for section, page, and lg.