This document defines the styling rules and conventions used throughout the shadcn/ui repository and recommended for projects using the system. It covers semantic color architecture, spacing patterns, utility class conventions, and the technical implementation of theme tokens.
The styling system in shadcn/ui is built on Tailwind CSS and CSS Variables. The primary goal is to provide a themeable design system where components are decoupled from specific color values, allowing for easy customization and automatic dark mode support through semantic tokens. This architecture ensures that components added via the CLI integrate seamlessly with the user's project theme skills/shadcn/SKILL.md8-10
shadcn/ui uses a semantic color token system where all colors are defined as CSS variables. Components reference these semantic tokens exclusively via Tailwind utility classes, never raw hex or Oklch values skills/shadcn/SKILL.md27
The following diagram illustrates the data flow from raw CSS variables to component styling, highlighting the mapping from the CSS layer to Tailwind utilities.
Title: Styling Data Flow Architecture
Sources: skills/shadcn/customization.md18-47 skills/shadcn/customization.md104-110
The system uses background/foreground pairs. The base token (e.g., primary) controls the surface, while the -foreground suffix controls text and icons on that surface skills/shadcn/customization.md27-28
| Token | Purpose | Foreground Pair |
|---|---|---|
background | Page background and default text | foreground |
card | Elevated surfaces (Cards, panels) | card-foreground |
popover | Floating surfaces (Menus, Tooltips) | popover-foreground |
primary | High-emphasis actions/brand | primary-foreground |
secondary | Lower-emphasis surfaces | secondary-foreground |
muted | Subtle surfaces/placeholders | muted-foreground |
accent | Hover and accent states | accent-foreground |
destructive | Errors and destructive actions | destructive-foreground |
border | Default borders and separators | — |
input | Form control borders | — |
ring | Focus rings and outlines | — |
chart-1..5 | Data visualization colors | — |
sidebar-* | Sidebar-specific colors | — |
surface | Secondary surface | surface-foreground |
Sources: skills/shadcn/customization.md30-45
The repository strictly enforces the use of gap-* with flex or grid instead of space-x-* or space-y-*. This provides better compatibility with RTL (Right-to-Left) layouts and prevents issues with hidden children in the DOM skills/shadcn/SKILL.md36
<div className="space-y-4"> skills/shadcn/rules/styling.md117<div className="flex flex-col gap-4"> skills/shadcn/rules/styling.md116When RTL support is enabled (via shadcn init --rtl), the CLI uses transformers to convert physical properties (left/right) into logical properties (start/end) to ensure layouts mirror correctly skills/shadcn/cli.md38
ml-4 becomes ms-4 (margin-start).pr-2 becomes pe-2 (padding-end).Sources: skills/shadcn/SKILL.md36-40 skills/shadcn/cli.md38 skills/shadcn/rules/styling.md109-121
To maintain a clean and consistent codebase, specific Tailwind shorthands are preferred over verbose manual styling.
size-*)When width and height are equal, the size-* utility must be used skills/shadcn/SKILL.md37
className="w-10 h-10" skills/shadcn/rules/styling.md121className="size-10" skills/shadcn/rules/styling.md120Use the truncate shorthand instead of manually defining overflow and white-space rules skills/shadcn/SKILL.md38
overflow-hidden text-ellipsis whitespace-nowrap skills/shadcn/rules/styling.md131truncate skills/shadcn/rules/styling.md129.cn-*)The repository uses style-specific CSS classes (e.g., .cn-button, .cn-alert) to define the visual aesthetic of components within different presets like Nova, Lyra, or Mira. These classes use @apply to map Tailwind utilities to the component structure apps/v4/registry/styles/style-nova.css149-151
Title: Component Style Implementation (Nova Style)
Sources: apps/v4/registry/styles/style-nova.css149-151 apps/v4/registry/styles/style-lyra.css145-147
data-icon)Icons within buttons should not use manual margin or sizing classes. Instead, they use the data-icon attribute which is targeted by the component's internal CSS. Icons are passed as objects, not string keys skills/shadcn/SKILL.md74-78
Title: Button Icon Styling Implementation
Sources: skills/shadcn/SKILL.md76-78 apps/v4/registry/styles/style-nova.css178-182
cn())All conditional styling must use the cn() utility, which wraps clsx and tailwind-merge. This ensures that utility conflicts (e.g., two different px- classes) are resolved correctly by giving precedence to the last class skills/shadcn/SKILL.md40
Sources: skills/shadcn/rules/styling.md141-157
shadcn/ui supports "presets" that define visual aesthetics through CSS variables and configurations. These can be applied to existing projects using the CLI skills/shadcn/customization.md66-81
nova, vega, sera), encoded codes, or URLs skills/shadcn/customization.md66-81apply command overwrites existing UI components, fonts, and CSS variables to match the new preset skills/shadcn/cli.md45-51--radius. Components derive values using calc(var(--radius) - 2px) skills/shadcn/customization.md135-137| Pattern | Rule | Reason |
|---|---|---|
| Raw Colors | No bg-blue-500 | Breaks theming and dark mode. skills/shadcn/rules/styling.md25 |
| Manual Dark Mode | No dark:bg-black | Use semantic tokens like bg-background. skills/shadcn/rules/styling.md137 |
| Z-Index | No manual z-index | Overlays like Dialog handle their own stacking. skills/shadcn/rules/styling.md163 |
| Layout Overrides | className for layout only | Do not override component colors/typography. skills/shadcn/rules/styling.md84 |
| Icon Sizing | No size-4 on icons | Components handle icon sizing via CSS. skills/shadcn/SKILL.md77 |
| Form Layout | No raw div for forms | Use FieldGroup + Field. skills/shadcn/SKILL.md45 |
| Animations | No custom @keyframes | Use shimmer or scroll-fade utilities. skills/shadcn/rules/styling.md167-186 |
Sources: skills/shadcn/rules/styling.md1-186 skills/shadcn/SKILL.md33-50 skills/shadcn/customization.md1-140
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.