shadcn ui : Core Blocks
Blocks are shadcn's whole-page distribution surface. They are NOT a separate technology from components : they are multi-file scaffolds copied into the consumer project via the same shadcn add CLI, governed by the same ownership doctrine. ALWAYS treat a block as a starting point for a page, NEVER as an immutable template.
Quick Reference
Block in one sentence
ALWAYS describe a block as : a multi-file composition of shadcn components, copied into the consumer project as owned source code, that delivers a complete page or large UI surface (dashboard, login page, sidebar shell). Components are building bricks ; blocks are pre-stacked walls.
The blocks gallery is its own surface : https://ui.shadcn.com/blocks (distinct from https://ui.shadcn.com/components). Verified verbatim from the gallery : "Clean, modern building blocks. Copy and paste into your apps. Works with all React frameworks. Open Source. Free forever."
Four invariants
- ALWAYS install a block with
pnpm dlx shadcn@latest add <block-id>(ornpx,bunx,yarn dlx). The CLI command is IDENTICAL to component install ; the block-id (e.g.dashboard-01,sidebar-07,login-03) signals the multi-file scaffold. - ALWAYS expect MULTIPLE files to be written when adding a block (page entry + sub-components + data file). NEVER assume a block is a single file like a component.
- ALWAYS run
shadcn add <block-id> --diffbefore re-running on an already-customised block. NEVER--overwriteblind ; the block is your code now. - ALWAYS pick ONE style enum value per project at
inittime and keep it. NEVER mixnew-yorkandseraandlumablocks in the same project ; visual coherence breaks.
Block versus component : decision in one line
ALWAYS choose a BLOCK when the unit of work is a whole page or major layout shell. ALWAYS choose individual COMPONENTS when composing a custom layout from scratch or extending an existing page with one new control.
Decision Tree 1 : Block or hand-composed components?
Q1. Do you need a whole-page surface (login page, full dashboard, sidebar shell, calendar app)?
no → ALWAYS hand-compose with individual components. See shadcn-core-cli.
yes → Q2
Q2. Does the shadcn blocks gallery offer a category that matches?
Categories observed at /blocks (verified 2026-05-19) :
dashboard, sidebar, login, signup, authentication, calendar
no → ALWAYS hand-compose ; do NOT force-fit an unrelated block
yes → Q3
Q3. Will the team customise the layout heavily (rearrange sections, swap data sources)?
yes → ALWAYS use the block as a starter, then edit freely (Open Code pillar)
no → ALWAYS use the block as-is, but still commit it as project source
Decision Tree 2 : Which style enum value?
The style field in components.json selects the visual character of every component and block copied into the project. It is set at init time and is immutable after init.
Q1. Is this a NEW project being initialised in 2026?
no → ALWAYS keep the existing `style` value. NEVER edit it post-init.
yes → Q2
Q2. What visual character does the design language need?
typography-driven, editorial, print-design feel
→ ALWAYS choose `sera` (introduced Apr 2026,
CLI >= 4.3.0). Underline controls, uppercase
headings, typographic emphasis.
soft, ambient, gradient-friendly, modern SaaS feel
→ ALWAYS choose `luma` (introduced Mar 2026,
CLI >= 4.1.2). Lighter visual weight.
geometric, design-system-grade, the modern default
→ ALWAYS choose `new-york`. Tight radii,
opinionated defaults. Recommended for
most new projects.
legacy compatibility with pre-2024 shadcn projects only
→ ALWAYS choose `default` (the original
style ; deprecated for new work but
retained for compatibility).
ALWAYS install blocks AFTER init so they inherit the chosen style. NEVER attempt to "switch style" mid-project by editing components.json ; the only correct switch is a full re-init + re-add of every component and block.
Decision Tree 3 : Adding a block to the project
Q1. Has `pnpm dlx shadcn@latest init` been run (does `components.json` exist)?
no → ALWAYS run `init` first and choose `style`, `baseColor`,
`cssVariables`, aliases. These are immutable.
yes → Q2
Q2. Does the local copy of the block already exist (e.g. `app/dashboard/page.tsx` + `components/dashboard/...`)?
no → `pnpm dlx shadcn@latest add <block-id>` copies the full scaffold.
yes → Q3 (re-install scenario)
Q3. Has the local copy been customised?
no → `pnpm dlx shadcn@latest add <block-id> --overwrite` is safe.
yes → ALWAYS run `--diff` first, decide per file : skip, overwrite,
or hand-merge. See `references/examples.md`.
Decision Tree 4 : Did the block break after a rerun?
Q1. Did you re-run `shadcn add <block-id> --overwrite` and lose customisations?
yes → ALWAYS recover from git. The local block files ARE your version control.
See [shadcn-errors-cli-sync-mismatch] for the merge workflow.
no → Q2
Q2. Did the visual style suddenly look inconsistent across the page?
yes → check whether multiple blocks installed at different times used
different `style` values (highly unlikely if `components.json` is
stable, but possible if `style` was edited manually). See
`references/anti-patterns.md` anti-pattern 3.
no → Q3
Q3. Did an internal sub-component fail to import?
yes → ALWAYS verify imports point at the LOCAL alias where the block was
copied (e.g. `@/components/dashboard/...`), NOT at any external
package path. See `references/anti-patterns.md` anti-pattern 4.
no → unrelated to blocks ; consult the component-specific error skill
Patterns
Pattern 1 : Block catalog overview
Verified at https://ui.shadcn.com/blocks (2026-05-19). The gallery groups blocks into categories. Headline examples observed :
| Category | Headline blocks (verified IDs) | Typical use |
|---|---|---|
| Dashboard | dashboard-01 |
Full admin / SaaS dashboard with sidebar, header, charts, data table |
| Sidebar | sidebar-03, sidebar-07 |
Standalone sidebar shells with various navigation patterns |
| Login | login-03, login-04 |
Authentication entry forms with branded layout |
| Signup | (gallery entry, verify current IDs at /blocks) | Signup / registration entry forms |
| Authentication | (gallery entry) | Broader auth flows (forgot password, two-factor, etc.) |
| Calendar | (gallery entry) | Calendar-centric layouts |
ALWAYS browse https://ui.shadcn.com/blocks before committing to a block-id ; the gallery is the canonical inventory. NEVER assume a block-id from memory or training data ; verify at install time.
Pattern 2 : Block-add CLI flow
The CLI command is the SAME as for components ; the block-id is what signals a multi-file scaffold :
# component (single file output)
pnpm dlx shadcn@latest add button
# block (multi-file scaffold output)
pnpm dlx shadcn@latest add dashboard-01
After add dashboard-01 the CLI typically copies :
- A page entry (e.g.
app/dashboard/page.tsxon Next.js App Router projects). - A folder of sub-components (e.g.
components/dashboard/). - Optionally a data file (e.g.
app/dashboard/data.json) when the block demos data-driven UI. - Any missing primitives the block depends on (e.g.
components/ui/sidebar.tsx,components/ui/data-table.tsx).
The exact file list is documented per-block at the gallery preview. ALWAYS run shadcn add <block-id> --dry-run if uncertain about file output ; the dry-run prints the planned writes without touching disk. ALWAYS run --view to inspect a single file before installing.
For full CLI flag detail (--overwrite, --diff, --dry-run, --view, --yes, --path), see shadcn-core-cli.
Pattern 3 : Style enum (default / new-york / sera / luma)
Verified from https://ui.shadcn.com/docs/changelog (2026-05-19) :
| Style | Introduced | CLI minimum | Character |
|---|---|---|---|
default |
Original (pre-2024) | any | Legacy. Deprecated for new projects. Retained for backward compatibility. |
new-york |
2024 | any | Geometric, tight radii, design-system-grade. The conventional 2025-2026 choice. |
luma |
March 2026 | shadcn@4.1.2 |
Soft, ambient, gradient-friendly. SaaS-modern visual weight. |
sera |
April 2026 | shadcn@4.3.0 |
Typography-first. Built on print design principles. Underline controls, uppercase headings. |
The style is selected at init time :
pnpm dlx shadcn@latest init # interactive prompt selects style
# or non-interactively :
pnpm dlx shadcn@latest init --style new-york
ALWAYS choose ONE style and keep it. NEVER mix styles within a project ; the visual language fragments because radii, spacing, and typographic defaults differ per style. The style field in components.json is immutable post-init in the operational sense : the CLI does not provide a switch command, and any attempt to edit it manually leaves the already-installed components in the OLD style.
Pattern 4 : Customisation after add (ownership reinforcement)
Blocks inherit the Open Code pillar from shadcn-core-architecture. After pnpm dlx shadcn@latest add dashboard-01 the consumer owns every file copied. Five concrete obligations :
- ALWAYS commit every block file (
app/dashboard/page.tsx,components/dashboard/*, data files) to source control as first-class application code. - ALWAYS lint and type-check block files together with the rest of the codebase.
- ALWAYS expect re-adding the block to be a MANUAL merge operation, not an automatic upgrade.
- ALWAYS feel free to delete or refactor any sub-component shipped with the block ; if the dashboard sidebar is irrelevant, remove its file.
- ALWAYS prefer editing the block files in place over wrapping them in further indirection. Wrapper components defeat the Open Code pillar.
Pattern 5 : Block and component composition
Blocks and components compose without friction. A common pattern : install a block for the page shell, then drop hand-composed components into the body slot.
// app/dashboard/page.tsx (copied from `dashboard-01` block, then customised)
import { SidebarProvider, SidebarInset } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/dashboard/app-sidebar" // block sub-component
import { CustomMetricsPanel } from "@/components/metrics-panel" // hand-built component
export default function DashboardPage() {
return (
<SidebarProvider>
<AppSidebar />
<SidebarInset>
<CustomMetricsPanel />
</SidebarInset>
</SidebarProvider>
)
}
ALWAYS treat a block as the page skeleton and components as the organs inside it. NEVER feel obliged to keep block sub-components untouched ; they are owned code and can be replaced wholesale.
Pattern 6 : Block vs custom-registry relationship
Blocks live in the default @shadcn registry alongside components. The registry.json schema (see shadcn-core-registry) accepts a type discriminator that identifies the registry item as a block (registry:block) or a component (registry:ui, registry:lib, etc.). The CLI uses this discriminator internally to decide how to copy files. Consumers do NOT supply the type ; the registry does.
Custom registries (private internal design systems) CAN publish their own blocks by setting type: "registry:block" on registry items. ALWAYS see shadcn-core-registry for the full schema. NEVER hand-edit registry JSON files in the consumer project ; the registry is the publisher's surface, not the consumer's.
Pattern 7 : Versioning quirks specific to blocks
Blocks depend on specific components (a dashboard block depends on Sidebar, DataTable, Card, etc.). When the shadcn project ships a new version of an underlying component, the block may quietly depend on the new API surface. Implications :
- ALWAYS pin the working state of block files in git immediately after
add. The committed source IS the version. - ALWAYS verify breaking changes via https://ui.shadcn.com/docs/changelog BEFORE re-adding a block (especially after a Calendar v9 transition or cmdk drift incident).
- ALWAYS lock underlying runtime dependencies (
radix-ui,cva,tailwind-merge,react-day-picker,cmdk,lucide-react) inpackage.jsonso that re-adding a block does not silently install a new major of an underlying primitive.
NEVER expect blocks to auto-upgrade. The ownership doctrine is non-negotiable.
Anti-patterns (summary ; full catalogue in references/anti-patterns.md)
NEVER do these :
- NEVER treat a block as an immutable starter template : a block is owned code and SHOULD be edited freely after
add. - NEVER re-run
shadcn add <block-id> --overwriteon a customised block without first running--diff: the overwrite is irreversible and loses work. - NEVER mix multiple
styleenum values in one project : visual coherence breaks because radii, spacing, and typography differ per style. - NEVER import a block sub-component from any path other than the local alias where it was copied (e.g.
@/components/dashboard/...). - NEVER expect blocks to auto-update when shadcn ships new block revisions : they are local source ; upgrades are manual re-add + merge.
Reference Links
- references/methods.md : CLI signatures for
add, registry-itemtypediscriminator, exact style-enum values and minimum CLI versions - references/examples.md : dashboard block install, file-output expectations, customisation diff, style switch workaround, block + component composition
- references/anti-patterns.md : five canonical anti-patterns with WHY each fails and the fix
Companion Skills
- shadcn-core-architecture : ownership doctrine reinforcement (blocks obey the same Open Code pillar)
- shadcn-core-cli : full CLI surface (
init,add,--diff,--overwrite,--dry-run,--view) - shadcn-core-registry :
registry.jsonschema,type: "registry:block"discriminator - shadcn-core-theming : how the style enum interacts with CSS variables and dark mode
- shadcn-errors-cli-sync-mismatch : recovering from accidental overwrite of customised blocks
Sources
All claims in this skill trace to URLs in SOURCES.md :
- https://ui.shadcn.com/blocks (gallery inventory, categories, headline block IDs, verbatim tagline)
- https://ui.shadcn.com/docs/cli (the
addcommand and its flags, identical for blocks and components) - https://ui.shadcn.com/docs/changelog (style enum additions :
lumaMarch 2026,seraApril 2026, CLI version gates) - https://ui.shadcn.com/docs/components-json (style field semantics, immutability after init)
- https://ui.shadcn.com/docs/registry (registry item type discriminator)
Verified 2026-05-19.