shadcn/ui A framework for building ui, components and design systems. Components are added as source code to the user's project via the CLI. IMPORTANT: Run all CLI commands using the project's package runner: npx shadcn@latest , pnpm dlx shadcn@latest , or bunx --bun shadcn@latest — based on the project's packageManager . Examples below use npx shadcn@latest but substitute the correct runner for the project. Current Project Context !`npx shadcn@latest info --json 2
/dev/ null || echo ' { "error" : "No shadcn project found. Run shadcn init first." } '` The JSON above contains the project config and installed components. Use npx shadcn@latest docs
to get documentation and example URLs for any component. Principles Use existing components first. Use npx shadcn@latest search to check registries before writing custom UI. Check community registries too. Compose, don't reinvent. Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table. Use built-in variants before custom styles. variant="outline" , size="sm" , etc. Use semantic colors. bg-primary , text-muted-foreground — never raw values like bg-blue-500 . Critical Rules These rules are always enforced . Each links to a file with Incorrect/Correct code pairs. Styling & Tailwind → styling.md className for layout, not styling. Never override component colors or typography. No space-x- or space-y- . Use flex with gap- . For vertical stacks, flex flex-col gap- . Use size- when width and height are equal. size-10 not w-10 h-10 . Use truncate shorthand. Not overflow-hidden text-ellipsis whitespace-nowrap . No manual dark: color overrides. Use semantic tokens ( bg-background , text-muted-foreground ). Use cn() for conditional classes. Don't write manual template literal ternaries. No manual z-index on overlay components. Dialog, Sheet, Popover, etc. handle their own stacking. Forms & Inputs → forms.md Forms use FieldGroup + Field . Never use raw div with space-y- or grid gap-* for form layout. InputGroup uses InputGroupInput / InputGroupTextarea . Never raw Input / Textarea inside InputGroup . Buttons inside inputs use InputGroup + InputGroupAddon . Option sets (2–7 choices) use ToggleGroup . Don't loop Button with manual active state. FieldSet + FieldLegend for grouping related checkboxes/radios. Don't use a div with a heading. Field validation uses data-invalid + aria-invalid . data-invalid on Field , aria-invalid on the control. For disabled: data-disabled on Field , disabled on the control. Component Structure → composition.md Items always inside their Group. SelectItem → SelectGroup . DropdownMenuItem → DropdownMenuGroup . CommandItem → CommandGroup . Use asChild (radix) or render (base) for custom triggers. Check base field from npx shadcn@latest info . → base-vs-radix.md Dialog, Sheet, and Drawer always need a Title. DialogTitle , SheetTitle , DrawerTitle required for accessibility. Use className="sr-only" if visually hidden. Use full Card composition. CardHeader / CardTitle / CardDescription / CardContent / CardFooter . Don't dump everything in CardContent . Button has no isPending / isLoading . Compose with Spinner + data-icon + disabled . TabsTrigger must be inside TabsList . Never render triggers directly in Tabs . Avatar always needs AvatarFallback . For when the image fails to load. Use Components, Not Custom Markup → composition.md Use existing components before custom markup. Check if a component exists before writing a styled div . Callouts use Alert . Don't build custom styled divs. Empty states use Empty . Don't build custom empty state markup. Toast via sonner . Use toast() from sonner . Use Separator instead of
or
.
Key Patterns
These are the most common patterns that differentiate correct shadcn/ui code. For edge cases, see the linked rule files above.
// Form layout: FieldGroup + Field, not div + Label.
<
FieldGroup
>
<
Field
>
<
FieldLabel
htmlFor
=
"
email
"
>
Email
FieldLabel
>
<
Input
id
=
"
email
"
/>
Field
>
FieldGroup
>
// Validation: data-invalid on Field, aria-invalid on the control.
<
Field
data-invalid
>
<
FieldLabel
>
Email
FieldLabel
>
<
Input
aria-invalid
/>
<
FieldDescription
>
Invalid email.
FieldDescription
>
Field
>
// Icons in buttons: data-icon, no sizing classes.
<
Button
>
<
SearchIcon
data-icon
=
"
inline-start
"
/>
Search
Button
>
// Spacing: gap-*, not space-y-*.
<
div
className
=
"
flex flex-col gap-4
"
>
// correct
<
div
className
=
"
space-y-4
"
>
// wrong
// Equal dimensions: size-*, not w-* h-*.
<
Avatar
className
=
"
size-10
"
>
// correct
<
Avatar
className
=
"
w-10 h-10
"
>
// wrong
// Status colors: Badge variants or semantic tokens, not raw colors.
<
Badge
variant
=
"
secondary
"
>
+20.1%
Badge
>
// correct
<
span
className
=
"
text-emerald-600
"
>
+20.1%
span
>
// wrong
Component Selection
Need
Use
Button/action
Button
with appropriate variant
Form inputs
Input
,
Select
,
Combobox
,
Switch
,
Checkbox
,
RadioGroup
,
Textarea
,
InputOTP
,
Slider
Toggle between 2–5 options
ToggleGroup
+
ToggleGroupItem
Data display
Table
,
Card
,
Badge
,
Avatar
Navigation
Sidebar
,
NavigationMenu
,
Breadcrumb
,
Tabs
,
Pagination
Overlays
Dialog
(modal),
Sheet
(side panel),
Drawer
(bottom sheet),
AlertDialog
(confirmation)
Feedback
sonner
(toast),
Alert
,
Progress
,
Skeleton
,
Spinner
Command palette
Command
inside
Dialog
Charts
Chart
(wraps Recharts)
Layout
Card
,
Separator
,
Resizable
,
ScrollArea
,
Accordion
,
Collapsible
Empty states
Empty
Menus
DropdownMenu
,
ContextMenu
,
Menubar
Tooltips/info
Tooltip
,
HoverCard
,
Popover
Key Fields
The injected project context contains these key fields:
aliases
→ use the actual alias prefix for imports (e.g.
@/
,
~/
), never hardcode.
isRSC
→ when
true
, components using
useState
,
useEffect
, event handlers, or browser APIs need
"use client"
at the top of the file. Always reference this field when advising on the directive.
tailwindVersion
→
"v4"
uses
@theme inline
blocks;
"v3"
uses
tailwind.config.js
.
tailwindCssFile
→ the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one.
style
→ component visual treatment (e.g.
nova
,
vega
).
base
→ primitive library (
radix
or
base
). Affects component APIs and available props.
iconLibrary
→ determines icon imports. Use
lucide-react
for
lucide
,
@tabler/icons-react
for
tabler
, etc. Never assume
lucide-react
.
resolvedPaths
→ exact file-system destinations for components, utils, hooks, etc.
framework
→ routing and file conventions (e.g. Next.js App Router vs Vite SPA).
packageManager
→ use this for any non-shadcn dependency installs (e.g.
pnpm add date-fns
vs
npm install date-fns
).
See
cli.md —
info
command
for the full field reference.
Component Docs, Examples, and Usage
Run
npx shadcn@latest docs
to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content.
npx shadcn@latest docs button dialog
select
When creating, fixing, debugging, or using a component, always run
npx shadcn@latest docs
and fetch the URLs first.
This ensures you're working with the correct API and usage patterns rather than guessing.
Workflow
Get project context
— already injected above. Run
npx shadcn@latest info
again if you need to refresh.
Check installed components first
— before running
add
, always check the
components
list from project context or list the
resolvedPaths.ui
directory. Don't import components that haven't been added, and don't re-add ones already installed.
Find components
—
npx shadcn@latest search
.
Get docs and examples
— run
npx shadcn@latest docs
to get URLs, then fetch them. Use
npx shadcn@latest view
to browse registry items you haven't installed. To preview changes to installed components, use
npx shadcn@latest add --diff
.
Install or update
—
npx shadcn@latest add
. When updating existing components, use
--dry-run
and
--diff
to preview changes first (see
Updating Components
below).
Fix imports in third-party components
— After adding components from community registries (e.g.
@bundui
,
@magicui
), check the added non-UI files for hardcoded import paths like
@/components/ui/...
. These won't match the project's actual aliases. Use
npx shadcn@latest info
to get the correct
ui
alias (e.g.
@workspace/ui/components
) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project.
Review added components
— After adding a component or block from any registry,
always read the added files and verify they are correct
. Check for missing sub-components (e.g.
SelectItem
without
SelectGroup
), missing imports, incorrect composition, or violations of the
Critical Rules
. Also replace any icon imports with the project's
iconLibrary
from the project context (e.g. if the registry item uses
lucide-react
but the project uses
hugeicons
, swap the imports and icon names accordingly). Fix all issues before moving on.
Registry must be explicit
— When the user asks to add a block or component,
do not guess the registry
. If no registry is specified (e.g. user says "add a login block" without specifying
@shadcn
,
@tailark
, etc.), ask which registry to use. Never default to a registry on behalf of the user.
Switching presets
— Ask the user first:
reinstall
,
merge
, or
skip
?
Reinstall
:
npx shadcn@latest init --preset --force --reinstall
. Overwrites all components.
Merge
:
npx shadcn@latest init --preset --force --no-reinstall
, then run
npx shadcn@latest info
to list installed components, then for each installed component use
--dry-run
and
--diff
to
smart merge
it individually.
Skip
:
npx shadcn@latest init --preset --force --no-reinstall
. Only updates config and CSS, leaves components as-is.
Important
: Always run preset commands inside the user's project directory. The CLI automatically preserves the current base (
base
vs
radix
) from
components.json
. If you must use a scratch/temp directory (e.g. for
--dry-run
comparisons), pass
--base
explicitly — preset codes do not encode the base.
Updating Components
When the user asks to update a component from upstream while keeping their local changes, use
--dry-run
and
--diff
to intelligently merge.
NEVER fetch raw files from GitHub manually — always use the CLI.
Run
npx shadcn@latest add --dry-run
to see all files that would be affected.
For each file, run
npx shadcn@latest add --diff
to see what changed upstream vs local.
Decide per file based on the diff:
No local changes → safe to overwrite.
Has local changes → read the local file, analyze the diff, and apply upstream updates while preserving local modifications.
User says "just update everything" → use
--overwrite
, but confirm first.
Never use
--overwrite
without the user's explicit approval.
Quick Reference
# Create a new project.
npx shadcn@latest init
--name
my-app
--preset
base-nova
npx shadcn@latest init
--name
my-app
--preset
a2r6bw
--template
vite
# Create a monorepo project.
npx shadcn@latest init
--name
my-app
--preset
base-nova
--monorepo
npx shadcn@latest init
--name
my-app
--preset
base-nova
--template
next
--monorepo
# Initialize existing project.
npx shadcn@latest init
--preset
base-nova
npx shadcn@latest init
--defaults
# shortcut: --template=next --preset=base-nova
# Add components.
npx shadcn@latest
add
button card dialog
npx shadcn@latest
add
@magicui/shimmer-button
npx shadcn@latest
add
--all
# Preview changes before adding/updating.
npx shadcn@latest
add
button --dry-run
npx shadcn@latest
add
button
--diff
button.tsx
npx shadcn@latest
add
@acme/form
--view
button.tsx
# Search registries.
npx shadcn@latest search @shadcn
-q
"sidebar"
npx shadcn@latest search @tailark
-q
"stats"
# Get component docs and example URLs.
npx shadcn@latest docs button dialog
select
# View registry item details (for items not yet installed).
npx shadcn@latest view @shadcn/button
Named presets:
base-nova
,
radix-nova
Templates:
next
,
vite
,
start
,
react-router
,
astro
(all support
--monorepo
) and
laravel
(not supported for monorepo)
Preset codes:
Base62 strings starting with
a
(e.g.
a2r6bw
), from
ui.shadcn.com
.
Detailed References
rules/forms.md
— FieldGroup, Field, InputGroup, ToggleGroup, FieldSet, validation states
rules/composition.md
— Groups, overlays, Card, Tabs, Avatar, Alert, Empty, Toast, Separator, Skeleton, Badge, Button loading
rules/icons.md
— data-icon, icon sizing, passing icons as objects
rules/styling.md
— Semantic colors, variants, className, spacing, size, truncate, dark mode, cn(), z-index
rules/base-vs-radix.md
— asChild vs render, Select, ToggleGroup, Slider, Accordion
cli.md
— Commands, flags, presets, templates
customization.md
— Theming, CSS variables, extending components
← 返回排行榜