Block vs Pattern vs Page
Three categories, one promotion ladder. Knowing where a piece of UI belongs is half the job of working in the system.
Definitions
The line between them is sharper than it looks. Read these once, refer back forever.
| Block | Pattern | Page | |
|---|---|---|---|
| Prefix | b- | x- | pg- |
| Scope | One thing on a page | A whole surface or interaction | A real product surface |
| Composes | Components (p-) | Blocks + components | Patterns + blocks + components |
| Behavior | Mostly visual | State machine + URL + keyboard | Real data + real flows |
| Reuse bar | Used 2+ times | Used on 2+ pages with same contract | One per surface |
| Example | Stat card | Data table | Overview dashboard |
The trap most teams fall into: calling a block a pattern because it's complicated. Complexity isn't the test. The test is whether the thing has behavior the system needs to guarantee across uses — a state machine, a URL convention, a keyboard contract.
Decision flowchart
Run any candidate through these four questions in order. Stop at the first answer.
Start: you have a candidate UI piece.
What is it — a block, a pattern, or a whole page?
Does it fill the whole content area of a screen?
Header + body + actions, with real data and real flows.
Yes → Page
Document under pg-. Composes patterns and blocks. See Compose a page.
No → continue
It's smaller than a page. Keep going.
Does it own a state machine, URL convention, or keyboard contract?
e.g. focus trap, hash for active tab, ←/→ navigation, websocket-stale refresh.
Yes → Pattern
Document under x-. Needs explicit guarantees. See Compose a pattern.
No → continue
It's a static composition. Keep going.
Is it more than one component arranged a specific way?
e.g. title + icon + delta number in a card; or icon + headline + lede + action in a row.
Yes → Block
Document under b-. A reusable arrangement of components.
No → continue
Only one component. Keep going.
It's a single component.
Document under p- (primitive / component), or extend an existing one with a variant.
Still not sure?
Default to block. Promote later when you see the second use case.
Six worked examples
Run the candidate through Q1–Q4. The categorization follows.
1 · Stat card → Block
A title, a big number, a tiny delta. Used in KPI grids, summary bars, and dashboards. No state machine, no URL — purely visual. Q1 no, Q2 no, Q3 yes → block. The card itself doesn't fetch or know its delta; the page passes them in.
2 · Data table → Pattern
Sticky header, sortable columns, row selection, pagination, bulk actions, URL-reflected filters, keyboard row navigation. Q1 no (it's part of a page), Q2 yes — state machine (empty / loading / selecting / bulk), URL contract for filters, keyboard contract → pattern.
3 · Modal → Pattern
Even though it looks like a block, a modal owns focus trap, escape-to-close, scroll lock, return-focus on dismiss, and a state machine (open / closing / open-with-form-dirty). Q1 no, Q2 yes → pattern. The modal's content is composed from blocks, but the modal itself is a pattern.
4 · Page header → Block
Title, lede, meta pills, up to three action buttons. Heavy visual structure, no behavior. Q1 no, Q2 no, Q3 yes → block. Every variant is a configuration of the same arrangement, not a different contract.
5 · Settings shell → Pattern
240px rail of sections on the left, a content column on the right with deep-linkable sections. The rail entry highlights based on scroll position; the URL hash reflects the active section; section anchors scroll smoothly on click. Q1 yes (it fills the screen), but it's the shell — Q2 yes (URL + keyboard) → pattern (specifically a shell pattern).
6 · Detail hero → Block
Big title, key identifying facts (status pill, amounts, dates), and the primary action for the record. No state machine, no URL — pure layout. Q1 no, Q2 no, Q3 yes → block. It lives inside the Detail view pattern, which does own the URL.
Common mis-categorizations
Promote a block to a pattern just because it has multiple parts. Page header has six parts and is still a block — none of them carry behavior. A pattern earns its prefix by owning a contract, not by being big.
Build a block with state and call it a block. If your "stat card" needs to fetch its own number, manage loading, and refresh on websocket, it's a small pattern in block clothing. Either lift the state out (recommended) or promote.
Make a pattern out of a single block. "Critical strip pattern" that's just the Critical strip block with no extra behavior — that's just the block. Delete the pattern doc.
Document a page when you mean a pattern. "Customers page" applies the Detail tabs pattern to a specific record. The pattern is reusable; the page is one concrete application of it.
What's next
Once you know what you're building, the next question is how it adapts to small screens. See Adapting blocks and patterns for mobile.