shadcn/ui
UI、コンポーネント、デザインシステムを構築するためのフレームワークです。コンポーネントはソースコードとしてCLIを介してユーザーのプロジェクトに追加されます。
重要: CLIコマンドはすべて、プロジェクトのパッケージランナーを使用して実行してください:
npx shadcn@latest、pnpm dlx shadcn@latest、またはbunx --bun shadcn@latest— プロジェクトのpackageManagerに基づいて選択します。以下の例ではnpx shadcn@latestを使用していますが、プロジェクトに適したランナーに置き換えてください。
現在のプロジェクトコンテキスト
!`npx shadcn@latest info --json`
上記のJSONにはプロジェクト設定とインストール済みコンポーネントが含まれています。コンポーネントのドキュメントと使用例のURLを取得するには、npx shadcn@latest docs <コンポーネント> を使用します。
原則
- 既存のコンポーネントを優先して使用する。 カスタムUIを作成する前に
npx shadcn@latest searchを使用してレジストリを確認してください。コミュニティレジストリも確認しましょう。 - 構成し、再発明しない。 設定ページ = Tabs + Card + フォームコントロール。ダッシュボード = Sidebar + Card + Chart + Table。
- カスタムスタイルの前に組み込みバリアントを使用する。
variant="outline"、size="sm"など。 - セマンティックカラーを使用する。
bg-primary、text-muted-foreground—bg-blue-500のような生の値は絶対に使用しない。
重要なルール
これらのルールは常に適用されます。各ルールは、不正/正しいコードペアを含むファイルにリンクされています。
スタイリングとTailwind → styling.md
classNameはレイアウトに使用し、スタイリングには使用しない。 コンポーネントの色やタイポグラフィを決して上書きしない。space-x-*やspace-y-*は使用しない。flexとgap-*を使用する。縦方向のスタックにはflex flex-col gap-*を使用する。- 幅と高さが等しい場合は
size-*を使用する。w-10 h-10ではなくsize-10を使用する。 truncateショートハンドを使用する。overflow-hidden text-ellipsis whitespace-nowrapとは書かない。- 手動での
dark:カラーオーバーライドはしない。 セマンティックトークン (bg-background、text-muted-foreground) を使用する。 - 条件付きクラスには
cn()を使用する。 手動でテンプレートリテラルの三項演算子を書かない。 - オーバーレイコンポーネントに手動で
z-indexを設定しない。 Dialog、Sheet、Popover などは自身の重なりを処理する。
フォームと入力 → forms.md
- フォームでは
FieldGroup+Fieldを使用する。 フォームレイアウトに生のdivとspace-y-*やgrid gap-*を使用しない。 InputGroupではInputGroupInput/InputGroupTextareaを使用する。InputGroup内で生のInput/Textareaを使用しない。- 入力内のボタンには
InputGroup+InputGroupAddonを使用する。 - オプションセット(2~7個の選択肢)には
ToggleGroupを使用する。 手動でアクティブ状態を管理するButtonのループは使用しない。 - 関連するチェックボックス/ラジオボタンのグループ化には
FieldSet+FieldLegendを使用する。 見出し付きのdivは使用しない。 - フィールドのバリデーションには
data-invalid+aria-invalidを使用する。Fieldにはdata-invalid、コントロールにはaria-invalidを使用する。無効状態の場合:Fieldにはdata-disabled、コントロールにはdisabledを使用する。
コンポーネント構造 → composition.md
- アイテムは常にそのグループの内側に配置する。
SelectItem→SelectGroup。DropdownMenuItem→DropdownMenuGroup。CommandItem→CommandGroup。 - カスタムトリガーには
asChild(radix) またはrender(base) を使用する。npx shadcn@latest infoでbaseフィールドを確認する。 → base-vs-radix.md - Dialog、Sheet、Drawer には常に Title が必要。 アクセシビリティのために
DialogTitle、SheetTitle、DrawerTitleが必要。視覚的に非表示にする場合はclassName="sr-only"を使用する。 - 完全な Card 構成を使用する。
CardHeader/CardTitle/CardDescription/CardContent/CardFooter。すべてをCardContentにまとめない。 - Button に
isPending/isLoadingはない。Spinner+data-icon+disabledで構成する。 TabsTriggerはTabsListの内側に配置する必要がある。 Tabs 内でトリガーを直接レンダリングしない。Avatarには常にAvatarFallbackが必要。 画像の読み込みに失敗した場合のために。
コンポーネントを使用し、カスタムマークアップは使用しない → composition.md
- カスタムマークアップの前に既存のコンポーネントを使用する。 スタイル付きの
divを書く前に、コンポーネントが存在するか確認する。 - 呼び出しには
Alertを使用する。 カスタムのスタイル付き div を構築しない。 - 空の状態には
Emptyを使用する。 カスタムの空状態マークアップを構築しない。 - Toast はプロジェクトのベースに従う。 Base UI プロジェクトでは、
toastコンポーネントのtoastを使用する。Radix および React Aria プロジェクトではsonnerのtoast()を使用する。 <hr>や<div className="border-t">の代わりにSeparatorを使用する。- ローディングプレースホルダーには
Skeletonを使用する。 カスタムのanimate-pulsediv は使用しない。 - カスタムスタイルの span の代わりに
Badgeを使用する。
アイコン → icons.md
Button内のアイコンにはdata-iconを使用する。 アイコンにdata-icon="inline-start"またはdata-icon="inline-end"を設定する。- コンポーネント内のアイコンにサイズクラスを付けない。 コンポーネントはCSSを介してアイコンのサイズを処理する。
size-4やw-4 h-4は使用しない。 - アイコンはオブジェクトとして渡し、文字列キーでは渡さない。
icon={CheckIcon}のようにし、文字列でのルックアップはしない。
チャットとメッセージング → chat.md
- チャットUIはチャットプリミティブを構成する。 会話には
MessageScroller、行にはMessage、表面にはBubbleを使用する。手作りされた bubble のdivや生のスクロールコンテナは決して使用しない。 MessageScrollerがスクロール動作を管理する。 ストリーミングフォロー、アンカー、最新へのジャンプ (MessageScrollerButton) は組み込まれている。useStickToBottom/ResizeObserverフックを書かない。- 添付ファイルには
Attachmentを使用し、システムノートと区切りにはMarkerを使用する。ItemカードやSeparator+ ラベルは使用しない。
CLI
- プリセットコードをデコードしたり、プリセットURLを手動で構築したりしない。
npx shadcn@latest preset decode <コード>、preset url <コード>、またはpreset open <コード>を使用する。プロジェクトを認識したプリセット検出には、npx shadcn@latest preset resolveを使用する。 - プリセットコードはCLIで直接適用する。 既存のプロジェクトには
npx shadcn@latest apply <コード>を使用し、初期化時にはnpx shadcn@latest init --preset <コード>を使用する。
主要なパターン
これらは、正しい shadcn/ui コードを区別する最も一般的なパターンです。エッジケースについては、上記のリンク先のルールファイルを参照してください。
// フォームレイアウト: FieldGroup + Field、div + Label ではない。
<FieldGroup>
<Field>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" />
</Field>
</FieldGroup>
// バリデーション: Field に data-invalid、コントロールに aria-invalid。
<Field data-invalid>
<FieldLabel>Email</FieldLabel>
<Input aria-invalid />
<FieldDescription>無効なメールアドレスです。</FieldDescription>
</Field>
// ボタン内のアイコン: data-icon、サイズクラスは付けない。
<Button>
<SearchIcon data-icon="inline-start" />
検索
</Button>
// スペーシング: space-y-* ではなく gap-*。
<div className="flex flex-col gap-4"> // 正しい
<div className="space-y-4"> // 間違い
// 等しい寸法: w-* h-* ではなく size-*。
<Avatar className="size-10"> // 正しい
<Avatar className="w-10 h-10"> // 間違い
// ステータスカラー: 生の色ではなく Badge バリアントまたはセマンティックトークン。
<Badge variant="secondary">+20.1%</Badge> // 正しい
<span className="text-emerald-600">+20.1%</span> // 間違い
コンポーネント選択
| ニーズ | 使用するもの |
|---|---|
| ボタン/アクション | 適切なバリアントを持つ Button |
| フォーム入力 | Input、Select、Combobox、Switch、Checkbox、RadioGroup、Textarea、InputOTP、Slider |
| 2~5個のオプション間の切り替え | ToggleGroup + ToggleGroupItem |
| データ表示 | Table、Card、Badge、Avatar |
| ナビゲーション | Sidebar、NavigationMenu、Breadcrumb、Tabs、Pagination |
| オーバーレイ | Dialog (モーダル)、Sheet (サイドパネル)、Drawer (ボトムシート)、AlertDialog (確認) |
| フィードバック | toast (Base UI)、sonner (Radix/Aria)、Alert、Progress、Skeleton、Spinner |
| コマンドパレット | Dialog 内の Command |
| チャート | Chart (Recharts ラッパー) |
| レイアウト | Card、Separator、Resizable、ScrollArea、Accordion、Collapsible |
| 空の状態 | Empty |
| メニュー | DropdownMenu、ContextMenu、Menubar |
| ツールチップ/情報 | Tooltip、HoverCard、Popover |
| チャット / 会話 UI | MessageScroller、Message、Bubble、Attachment、Marker |
主要フィールド
注入されるプロジェクトコンテキストには、以下の主要フィールドが含まれます:
aliases→ インポートには実際のエイリアスプレフィックス(例:@/、~/)を使用し、ハードコードしない。isRSC→trueの場合、useState、useEffect、イベントハンドラー、またはブラウザAPIを使用するコンポーネントは、ファイルの先頭に"use client"が必要。このディレクティブについてアドバイスする際は、常にこのフィールドを参照すること。tailwindVersion→"v4"は@theme inlineブロックを使用し、"v3"はtailwind.config.jsを使用する。tailwindCssFile→ カスタムCSS変数が定義されているグローバルCSSファイル。常にこのファイルを編集し、新しいファイルは作成しない。style→ コンポーネントのビジュアル処理(例:nova、vega)。base→ プリミティブライブラリ(radixまたはbase)。コンポーネントのAPIと利用可能なプロパティに影響する。iconLibrary→ アイコンのインポートを決定する。lucideの場合はlucide-react、tablerの場合は@tabler/icons-reactなどを使用する。lucide-reactを想定しない。resolvedPaths→ コンポーネント、ユーティリティ、フックなどの正確なファイルシステム上の宛先。framework→ ルーティングとファイルの規約(例: Next.js App Router vs Vite SPA)。packageManager→ shadcn 以外の依存関係のインストールにこれを使用する(例:pnpm add date-fnsとnpm install date-fnsの違い)。preset→ 現在のプロジェクトの解決済みプリセットコードと値。プリセット情報のみが必要な場合は、npx shadcn@latest preset resolve --jsonを使用する。
完全なフィールドリファレンスについては、cli.md — info コマンド を参照してください。
コンポーネントドキュメント、例、使用方法
コンポーネントのドキュメント、例、APIリファレンスのURLを取得するには、npx shadcn@latest docs <コンポーネント> を実行します。これらのURLを取得して実際のコンテンツを入手してください。
npx shadcn@latest docs button dialog select
コンポーネントを作成、修正、デバッグ、または使用する際は、常に最初に npx shadcn@latest docs を実行し、URLを取得してください。 これにより、推測ではなく、正しいAPIと使用パターンで作業していることが保証されます。
ワークフロー
- プロジェクトコンテキストを取得する — 上記で既に注入されています。リフレッシュが必要な場合は、
npx shadcn@latest infoを再度実行してください。 - 最初にインストール済みコンポーネントを確認する —
addを実行する前に、必ずプロジェクトコンテキストのcomponentsリストを確認するか、resolvedPaths.uiディレクトリをリストしてください。追加されていないコンポーネントをインポートしたり、既にインストールされているコンポーネントを再追加したりしないでください。 - コンポーネントを見つける —
npx shadcn@latest search。 - ドキュメントと例を取得する —
npx shadcn@latest docs <コンポーネント>を実行してURLを取得し、それらを取得します。インストールしていないレジストリアイテムを閲覧するにはnpx shadcn@latest viewを使用します。インストール済みコンポーネントへの変更をプレビューするには、npx shadcn@latest add --diffを使用します。 - インストールまたは更新する —
npx shadcn@latest add。既存のコンポーネントを更新する場合は、最初に--dry-runと--diffを使用して変更をプレビューします(以下の コンポーネントの更新 を参照)。 - サードパーティコンポーネントのインポートを修正する — コミュニティレジストリ(例:
@bundui、@magicui)からコンポーネントを追加した後、追加されたUI以外のファイルに@/components/ui/...のようなハードコードされたインポートパスがないか確認します。これらはプロジェクトの実際のエイリアスと一致しません。npx shadcn@latest infoを使用して正しいuiエイリアス(例:@workspace/ui/components)を取得し、それに応じてインポートを書き換えます。CLIは自身のUIファイルのインポートを書き換えますが、サードパーティのレジストリコンポーネントはプロジェクトと一致しないデフォルトパスを使用する場合があります。 - 追加されたコンポーネントを確認する — 任意のレジストリからコンポーネントまたはブロックを追加した後、追加されたファイルを常に読み、それらが正しいことを確認してください。サブコンポーネントの欠落(例:
SelectGroupのないSelectItem)、インポートの欠落、不適切な構成、または重要なルールの違反がないか確認してください。また、アイコンのインポートをプロジェクトコンテキストのiconLibraryに置き換えてください(例: レジストリアイテムがlucide-reactを使用しているがプロジェクトがhugeiconsを使用している場合、インポートとアイコン名をそれに応じて交換します)。先に進む前に、すべての問題を修正してください。 - レジストリは明示的に指定する必要がある — ユーザーがブロックやコンポーネントの追加を依頼した場合、レジストリを推測しないでください。レジストリが指定されていない場合(例: ユーザーが
@shadcn、@tailark、owner/repoなどを指定せずに「ログインブロックを追加して」と言った場合)、どのレジストリを使用するか尋ねてください。ユーザーに代わってレジストリをデフォルトにしないでください。 - プリセットの切り替え — 最初にユーザーに尋ねてください: 上書き、部分的、マージ、またはスキップ?
- 現在のプリセットを検査する:
npx shadcn@latest preset resolve。構造化された値が必要な場合は--jsonを使用します。 - 受け入れるプリセットを検査する:
npx shadcn@latest preset decode <コード>。preset url <コード>またはpreset open <コード>を使用してプリセットビルダーを共有または開きます。 - 上書き:
npx shadcn@latest apply <コード>。検出されたコンポーネント、フォント、CSS変数を上書きします。 - 部分的:
npx shadcn@latest apply <コード> --only theme,font。UIコンポーネントを再インストールせずに、選択したプリセット部分のみを更新します。サポートされる値はthemeとfontです。カンマ区切りの組み合わせが許可されます。iconは意図的にサポートされていません。アイコンの変更には完全なコンポーネントの再インストールが必要になる場合があるためです。 - マージ:
npx shadcn@latest apply <コード> --merge。既存のコンポーネントを保持しながら新しいコンポーネントを追加します(チェックを実行します)。 - スキップ: 何もしません。現在のプリセットをそのまま維持します。
- 現在のプリセットを検査する:
コンポーネントの更新
# 変更をプレビューする
npx shadcn@latest add button --dry-run --diff
# 変更を適用する
npx shadcn@latest add button
既存のコンポーネントを更新する際は、常に --dry-run と --diff を最初に使用し、どのように変更されるかを正確に確認してください。