- Next.js
shadcn/uiとは|使い方・導入手順とエラーの直し方をViteで実演
結論
shadcn/uiは、UI部品のソースを自分のプロジェクトにコピーして使うReactの部品集です。npmから読み込むライブラリではありません。
この記事でわかること
- Vite+Reactへの導入8手順とビルドの実物
- CLIが使えないときに手で置く手順と11部品
- エラー原文9件(TS 6のbaseUrl・ERESOLVE等)
shadcn/ui の部品は、CLI(コマンド)がレジストリ(部品のソースの置き場)から取ってきて、あなたのプロジェクトの components/ui/ に書き込みます。書き込まれた後は、自分で書いたコードと同じように編集できます。
flowchart TD
A[shadcn の CLI<br>init と add] --> B[レジストリ<br>部品のソース]
B --> C[components/ui に<br>ソースを書き込む]
C --> D[自分のコードとして<br>編集・コミット]
E[npm の UI ライブラリ] --> F[node_modules の中<br>import して使うだけ]
よく使う操作を先にまとめます。
| やりたいこと | コマンド・場所 | 補足 |
|---|---|---|
| 新しく始める | npx shadcn@latest init -t vite |
-t next で Next.js |
| 部品を足す | npx shadcn@latest add button |
components/ui/ に入る |
| 足す前に中身を見る | add button --dry-run / --view |
書き込まずに確認 |
| 色を変える | CSS の :root の --primary など |
部品のコードは変えない |
| ダークモード | <html> に dark クラス |
.dark の変数が効く |
| Radix UI で始める | npx shadcn@latest init -b radix |
既定は Base UI |
| 更新を確かめる | add button --diff |
自分の変更と見比べる |
| CLI が使えない | GitHub のソースを手で置く | 「Manual」の手順 |
| 設定ファイル | components.json |
CLI が読む。手動なら無くてよい |
確認環境:Ubuntu 24.04・Node.js 22.22.2・npm 10.9.7。create-vite 9.3.1 で作った React+TypeScript のプロジェクト(Vite 8.3.5・React 19.3.1・TypeScript 6.0.3)に、公式ドキュメントの Vite の手順と Manual Installation の手順で Tailwind CSS 4.3.3・shadcn 4.22.1・cn 0.5.0・class-variance-authority 0.7.1・radix-ui 1.8.1・lucide-react 1.61.0・tw-animate-css 1.4.0 を入れ、shadcn-ui/ui の GitHub のソース(2026年10月22日のコミット)から new-york-v4 スタイルの部品11個を手で置きました。フォームは react-hook-form 7.90.0・@hookform/resolvers 6.0.0・zod 4.6.7 です。npm run build と vite preview で動かし、Chromium 141(playwright-core 1.56.1)で色・フォームの検証・ダイアログ・ダークモードを確かめました。エラーは同じプロジェクトでわざと起こした原文です。shadcn の CLI は --help・migrate --list・init の選択肢と、レジストリ(ui.shadcn.com)に届かないときのエラーを実行して確かめ、init・add がレジストリから部品を取って書き込む動きは公式ドキュメント(ui.shadcn.com/docs と GitHub の apps/v4/content/docs)と CLI のソースで確かめました。MUI・Chakra UI・daisyUI は各公式のインストールのページと npm のパッケージ情報で確かめました(確認日 2026年10月22日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「shadcn/uiとは|使い方・導入手順とエラーの直し方をViteで実演」
shadcn/uiとは(読み方・何ができるか・無料か)
この節では、shadcn/ui が何で、どんな考え方で作られているかが分かります。
shadcn/ui は、ボタン・カード・ダイアログ・フォームなどの UI 部品を、ソースコードのまま自分のプロジェクトに入れて使う React 向けの部品集です。 公式の紹介文の最初の一文は「This is not a component library. It is how you build your component library.」(これは部品のライブラリではない。自分の部品のライブラリを作る方法だ)です。
名前の shadcn は作者の名前(ハンドル名)で、ライセンスの文面も「Copyright (c) 2023 shadcn」です。npm のパッケージ名(CLI)は shadcn、プロジェクト名は shadcn/ui と書き分けられます。
1Open Code
部品のソースがそのまま手元に入る。見た目や動きを、ラップや上書きではなく、コードを直接書き換えて変えられる。
2Composition
どの部品も同じ組み立て方(Card の中に CardHeader など)で使える。覚える API が少ない。
3Distribution
部品を JSON の形式(スキーマ)と CLI で配る仕組み。自分の部品を社内に配るレジストリも作れる。
4Beautiful Defaults と AI-Ready
そのままで整った見た目。コードが手元にあるので、AI のコーディングツールも読んで直せる。
部品の「動き」(キーボード操作・フォーカスの管理・ARIA 属性)は、Base UI・Radix UI・React Aria といったヘッドレス(見た目を持たない)ライブラリが受け持ちます。shadcn/ui は、その上に Tailwind CSS のクラスで見た目を付けた層です。動きの部分は npm の依存として更新され、見た目の層は自分のコードとして持つ、という分け方になっています。
shadcn/uiは無料で、商用でも使えるか
MIT ライセンスで公開されていて、無料です。 商用のアプリにも使えます。MIT ライセンスは、著作権表示とライセンスの文面をソフトウェアの複製に含めることを条件にしています。CLI の shadcn パッケージも、Radix UI(radix-ui)・Base UI(@base-ui/react)も npm 上のライセンスは MIT で、React Aria Components(react-aria-components)は Apache-2.0 です(2026年10月22日時点)。
いつ変わったか(2026年の主な変更)
shadcn/ui は変更が多く、半年前の解説と今の手順が違うことがあります。公式の変更履歴(Changelog)から、今の使い方に関わるものを並べます。
| 時期 | 変わったこと | 影響 |
|---|---|---|
| 2026年2月 | Radix の部品が radix-ui 1つのパッケージを使う形に |
@radix-ui/react-* が不要に |
| 2026年3月 | CLI v4(プリセット・--dry-run・--diff・--view・skills) |
1つのコードで配色・フォントを指定 |
| 2026年7月 | 新しいプロジェクトの既定が Base UI に | Radix は -b radix で選べる |
| 2026年7月 | React Aria も選べるように | --base aria |
| 2026年9月 | cn 関数が cn パッケージに |
lib/utils.ts が1行に |
2026年10月22日時点の CLI の最新版は shadcn 4.22.1(npm)です。以前の shadcn-ui というパッケージ名は 0.9.5 で止まっていて、npm で非推奨(deprecated)になっています。npx shadcn-ui@latest init と書かれた解説は、npx shadcn@latest init に読み替えます。
npmのUIライブラリとの違い(コピーして自分のコードにする仕組み)
この節では、「コピーして使う」とは具体的に何が起きるのかを、実際に置かれたファイルで確かめられます。
ボタンの角の丸みと色を、会社のデザインに合わせたいとき
src/components/ui/button.tsx にある。CSS 変数で色を変え、足りない種類はファイルに1行足す。変更は自分の Git の履歴に残るそのかわり、部品の更新は自動では届かない。上流の変更は --diff で見比べて取り込む
手元の Vite のプロジェクトに置いた Button のソースの先頭です(new-york-v4 スタイル)。中身は、class-variance-authority(cva)で「variant ごとの Tailwind のクラス」を決め、Radix UI の Slot で asChild を実現しているだけの、64行の React の関数です。
// src/components/ui/button.tsx(抜粋)
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "cn"
import { Slot } from "radix-ui"
const buttonVariants = cva(
"inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium ...",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-white hover:bg-destructive/90 ...",
outline: "border bg-background shadow-xs hover:bg-accent ...",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
link: "text-primary underline-offset-4 hover:underline",
},
size: { default: "h-9 px-4 py-2 has-[>svg]:px-3", sm: "...", lg: "...", icon: "size-9" /* ほか */ },
},
defaultVariants: { variant: "default", size: "default" },
}
)
ブラウザで描画されたボタンには、この default と size: default のクラスがそのまま付いていました。
default button class: inline-flex shrink-0 items-center justify-center gap-2 rounded-md text-sm font-medium whitespace-nowrap transition-all outline-none ... bg-primary text-primary-foreground hover:bg-primary/90 h-9 px-4 py-2 has-[>svg]:px-3
つまり shadcn/ui の部品は「Tailwind のクラスを並べた React の関数」です。 bg-primary の色は CSS 変数 --primary から来るので、色を変えたいときは部品ではなく CSS を変えます(テーマの節)。
cn関数は何をしているか
部品は、受け取った className を cn() で元のクラスと混ぜます。cn はクラス名をつなぎ、Tailwind のクラスがぶつかったら後のものを残す関数です。2026年9月から、clsx と tailwind-merge の組み合わせの代わりに cn パッケージを使います。手元で実行した結果です。
import { cn } from "cn";
console.log(cn("px-2 py-1 bg-primary", "px-4"));
console.log(cn("rounded-md", false && "hidden", undefined, ["text-sm", { "font-bold": true, italic: false }]));
console.log(cn("bg-primary text-primary-foreground", "bg-warning"));
py-1 bg-primary px-4
rounded-md text-sm font-bold
text-primary-foreground bg-warning
px-2 と px-4 がぶつかると後の px-4 だけが残りました。だから <Button className="px-8"> と書くと、部品のコードを変えずに横の余白だけを上書きできます。
「スタイル」とソースの関係(Base UI版の部品の中身)
GitHub の apps/v4/registry/bases/base/ui/button.tsx(Base UI 版)を開くと、クラスは Tailwind のクラスではなく cn-button-variant-default のような名前になっています。
// apps/v4/registry/bases/base/ui/button.tsx(抜粋)
import { Button as ButtonPrimitive } from "@base-ui/react/button"
const buttonVariants = cva(
"cn-button group/button inline-flex shrink-0 items-center justify-center ...",
{ variants: { variant: { default: "cn-button-variant-default", outline: "cn-button-variant-outline", /* ... */ } } }
)
この名前の中身は、スタイルごとの CSS(apps/v4/registry/styles/style-nova.css など8つ)で決まっています。
/* style-nova.css(抜粋) */
.cn-button-variant-default {
@apply bg-primary text-primary-foreground hover:bg-primary/80;
}
CLI は部品を入れるときに、選んだスタイル(Nova・Vega など)に合わせて cn-* を Tailwind のクラスに置き換えて書き込みます(shadcn 4.22.1 のソースに styleMap で置き換える処理があります)。GitHub の bases/ のファイルをそのままコピーしても色や形は付かないので、手で置くときは、公式サイトの各部品のページの「Manual」タブに表示されるソースか、Tailwind のクラスが入った形の new-york-v4 のソースを使います。
shadcn/uiの導入方法(Next.js・Vite・CLIのinitとadd)
この節では、公式の手順どおりに Next.js と Vite へ入れるコマンドと、init が何を聞いてくるかが分かります。
公式ドキュメントの入れ方は3通りです。
| 方法 | コマンド | 向いている場面 |
|---|---|---|
| shadcn/create | サイトで配色などを選び、出たコマンドを実行 | 見た目を見ながら決めたい |
| CLI で新規作成 | npx shadcn@latest init -t vite |
新しいプロジェクト |
| 既存のプロジェクト | Tailwind・@ の別名を整えてから init |
今あるアプリに足す |
-t(--template)に書けるのは next・vite・start・react-router・laravel・astro です。ドキュメントには Gatsby・TanStack Router・Remix・手動(Manual)の手順もあります。
Next.jsに入れる
create-next-app を「おすすめの既定値」で作ると、Tailwind CSS・App Router・@/* の別名が最初から入るので、そのまま init できます。
npx create-next-app@latest my-app
cd my-app
npx shadcn@latest init
npx shadcn@latest add button
// app/page.tsx
import { Button } from "@/components/ui/button"
export default function Home() {
return (
<main className="flex min-h-svh items-center justify-center">
<Button>Click me</Button>
</main>
)
}
--src-dir で作った場合は、別名が ./src/* を指し、ページは src/app/page.tsx です。components.json の rsc を true にすると、CLI はクライアントで動く部品に "use client" を自動で付けます(App Router の Server Components 向けの設定)。
Viteに入れる(既存のプロジェクト)
公式の Vite の手順(Existing Project)です。
npm create vite@latest # React + TypeScript を選ぶ
npm install tailwindcss @tailwindcss/vite
npm install -D @types/node
src/index.css を Tailwind の1行にし、tsconfig.json と tsconfig.app.json に @/* の別名を足し、vite.config.ts に Tailwind のプラグインと別名を足してから、init します。
npx shadcn@latest init
npx shadcn@latest add button
2026年10月22日時点の create-vite(9.3.1)では TypeScript 6.0.3 が入り、公式の手順どおりに baseUrl を書くとビルドが止まります。 手元で起きたエラーと直し方は、次の「手動導入」の節に実物で載せます。Vite のプロジェクトの作り方は関連記事「React環境構築をViteで行う手順|create viteの使い方」で扱っています。
initで選ぶもの(ベース・プリセット)
init は、部品の土台(ベース)とプリセット(配色・フォント・アイコン・角丸のまとめ)を聞いてきます。CLI 4.22.1 で init -t vite -b radix を実行したときに出た選択肢です。
? Which preset would you like to use? › - Use arrow-keys. Return to submit.
❯ Nova - Lucide / Geist
Vega
Maia
Lyra
Mira
Luma
Sera
Rhea
Custom
Nova を選ぶと、CLI は https://ui.shadcn.com/init?base=radix&style=nova&baseColor=neutral&theme=neutral&iconLibrary=lucide&font=geist&... に設定を取りに行きました(URL はエラーの文に出たもの)。プリセットの中身が「スタイル・ベースの色・アイコン・フォント・角丸」の組み合わせであることが分かります。
| init のオプション | 意味 |
|---|---|
-t, --template |
next・vite・start・react-router・laravel・astro |
-b, --base |
base(Base UI・既定)・radix・aria |
-p, --preset |
プリセットの名前かコード |
-n, --name |
新しいプロジェクトの名前 |
-d, --defaults |
--template=next --preset=nova で進める |
--monorepo |
モノレポで作る |
--rtl |
右から左に書く言語に対応 |
--pointer |
ボタンのカーソルを pointer にする |
--no-css-variables |
CSS 変数を使わず色のクラスを直接書く |
init は依存のインストール・cn の用意・CSS 変数の設定を行い、components.json を作ります。create は init の別名です。
addで部品を足す
npx shadcn@latest add card # 1つ
npx shadcn@latest add label select # まとめて
npx shadcn@latest add --all # 全部
npx shadcn@latest add button --dry-run # 書き込まずに何が入るか見る
npx shadcn@latest add button --view # 中身を表示
npx shadcn@latest add button --diff # 手元のファイルとの差分
add は components.json の aliases.ui(既定は @/components/ui)の場所にファイルを書き、部品が使う npm のパッケージも入れます。既にあるファイルを上書きするときは -o(--overwrite)を付けます(既定は上書きしない設定)。
CLIが使えないときの手動導入(Vite+Reactでビルドした実例)
この節では、CLI がレジストリに届かない環境で、公式の Manual の手順と GitHub のソースだけで shadcn/ui を動かすまでを、全部の出力つきで追えます。
CLIのエラー(レジストリに届かない)
会社のプロキシなどで ui.shadcn.com への通信が許可されていないと、init・add・info はどれも次の形で止まりました。
Something went wrong. Please check the error below for more details.
If the problem persists, please open an issue on GitHub.
Request to https://ui.shadcn.com/r/styles/new-york-v4/button.json failed, reason: Request was cancelled.
You can also try a previous version to see if that works:
npx shadcn@4.21.0 add button
components.json の style が new-york のプロジェクトでは、add button は r/styles/new-york-v4/button.json を取りに行っていました。CLI は部品のソースを毎回レジストリから取るので、この通信が通らない限り版を変えても結果は同じです。 通信の許可を頼めない場合は、公式ドキュメントの「Manual Installation」の手順で、ソースを手で置きます。
手動導入の手順(8ステップ)
Vite のプロジェクトを作る
npm create vite@latest で React+TypeScript を選び、npm install。
Tailwind CSS を入れる
tailwindcss と @tailwindcss/vite を入れ、Vite のプラグインに足す。
依存を入れる
Manual の手順の5つと、部品が使う radix-ui を入れる。
@ の別名を設定する
tsconfig.json・tsconfig.app.json の paths と、vite.config.ts の resolve.alias。
CSS を貼る
Manual の手順の CSS(Tailwind の読み込み・@theme inline・:root と .dark の変数)を src/index.css に。
cn を用意する
src/lib/utils.ts に export { cn } from "cn" の1行。
部品のソースを置く
GitHub の new-york-v4 の ui/ から必要なファイルを src/components/ui/ に置き、import のパスを直す。
components.json を置く
後で CLI が使えるようになったときのために置く。手動だけなら無くても動く。
1〜3:プロジェクトと依存
npm create vite@latest app -- --template react-ts
cd app
npm install
npm install tailwindcss @tailwindcss/vite
npm install shadcn class-variance-authority cn lucide-react tw-animate-css radix-ui
5つ目までは Manual の手順にある依存です。shadcn は CLI のパッケージですが、CSS の @import "shadcn/tailwind.css"(Base UI と Radix の共通の CSS のバリアントなど)のために依存に入ります。この依存を外したい場合は、npx shadcn@latest eject で CSS をファイルに書き出す方法があります。radix-ui は、置く部品(new-york-v4)が import しているので足しました。入った版です。
+-- @tailwindcss/vite@4.3.3
+-- class-variance-authority@0.7.1
+-- cn@0.5.0
+-- lucide-react@1.61.0
+-- radix-ui@1.8.1
+-- react@19.3.1
+-- shadcn@4.22.1
+-- tailwindcss@4.3.3
+-- tw-animate-css@1.4.0
+-- typescript@6.0.3
`-- vite@8.3.5
4:@の別名(TypeScript 6ではbaseUrlを書かない)
公式の Vite の手順は、tsconfig.json と tsconfig.app.json に baseUrl と paths を足す形です。そのとおりに書いて npm run build すると、TypeScript 6.0.3 で次のエラーになりました。
tsconfig.app.json(18,5): error TS5101: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0. Specify compilerOption '"ignoreDeprecations": "6.0"' to silence this error.
Visit https://aka.ms/ts6 for migration information.
paths は baseUrl が無くても、tsconfig のある場所からの相対パスとして働きます。 baseUrl の行だけを消すとビルドが通りました。
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
],
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
// tsconfig.app.json(compilerOptions の中に足す)
"paths": {
"@/*": ["./src/*"]
},
vite.config.ts は公式の形に、Vite 8 の警告が出ない書き方(__dirname の代わりに import.meta.dirname)を合わせました。__dirname のままでも動きますが、ビルドのたびに次の警告が出ました。
(!) Your Vite config uses features that are unsupported by `configLoader: 'native'`, which is planned to become the default in a future major version of Vite:
- `__dirname` (vite.config.ts:11:25). Use `import.meta.dirname` instead
// vite.config.ts
import path from "path"
import tailwindcss from "@tailwindcss/vite"
import react from "@vitejs/plugin-react"
import { defineConfig } from "vite"
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
"@": path.resolve(import.meta.dirname, "./src"),
},
},
})
Vite 8 には、tsconfig の paths を読む resolve.tsconfigPaths: true という設定もあります(既定は false)。alias の代わりにこれを書いても、開発サーバーで @/components/... が解決されました。
5〜6:CSSとcn
src/index.css には、Manual の手順の CSS(125行)を貼ります。先頭はこうなっています。
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: var(--background);
--color-primary: var(--primary);
/* ……色・角丸・サイドバーの変数が続く */
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--primary: oklch(0.205 0 0);
/* …… */
}
.dark {
--background: oklch(0.145 0 0);
--primary: oklch(0.922 0 0);
/* …… */
}
// src/lib/utils.ts
export { cn } from "cn"
7:部品のソースを置く
公式サイトの各部品のページには「Command」と「Manual」のタブがあり、Manual のタブに入れるパッケージとソースが表示されます。ここでは GitHub の公開リポジトリから、Tailwind のクラスが入った形の new-york-v4(Radix UI のスタイル)のソースを取りました。
git clone --depth 1 --filter=blob:none --sparse https://github.com/shadcn-ui/ui.git
cd ui && git sparse-checkout set apps/v4/registry/new-york-v4/ui && cd ..
R=ui/apps/v4/registry/new-york-v4/ui
for f in button card input label badge field separator textarea dialog dropdown-menu tabs; do
cp "$R/$f.tsx" app/src/components/ui/
done
リポジトリの中のファイルは、部品どうしを @/registry/new-york-v4/ui/label のようなパスで import しています。手で置いたら、ここを自分の @/components/ui/ に直します。 CLI はこれを components.json の aliases を見て自動で行います。
grep -l '@/registry' app/src/components/ui/*.tsx
# app/src/components/ui/dialog.tsx
# app/src/components/ui/field.tsx
sed -i 's#@/registry/new-york-v4/ui/#@/components/ui/#g' app/src/components/ui/*.tsx
(macOS の sed は sed -i '' 's#…#…#g' の形です。)置いた11ファイルは合わせて1,041行でした。
| ファイル | 行数 | 使っているもの |
|---|---|---|
button.tsx |
64 | cva・radix-ui の Slot |
card.tsx |
91 | div のみ |
dialog.tsx |
158 | radix-ui の Dialog・lucide-react・button |
dropdown-menu.tsx |
256 | radix-ui の DropdownMenu・lucide-react |
field.tsx |
248 | cva・label・separator |
tabs.tsx |
90 | cva・radix-ui の Tabs |
badge・input・label・separator・textarea |
17〜47 | label・separator は radix-ui |
8:components.json(CLIのため)
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
ビルドして動かした結果
npm run build
> app@0.0.0 build
> tsc -b && vite build
vite v8.3.5 building client environment for production...
transforming...
✓ 2151 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html 0.45 kB │ gzip: 0.29 kB
dist/assets/index-W4sOEtLW.css 45.33 kB │ gzip: 8.38 kB
dist/assets/index-BkvowQ6d.js 480.24 kB │ gzip: 152.09 kB
✓ built in 887ms
vite preview で開いた画面を、Chromium で調べた結果です。部品は data-slot 属性で見分けられます。
browser 141.0.7390.37
data-slot {"dropdown-menu-trigger":1,"card":1,"card-header":1,"card-title":1,"card-description":1,"badge":1,"card-content":1,"button":7,"tabs":1,"tabs-list":1,"tabs-trigger":2,"tabs-content":2,"field-group":1,"field":2,"field-label":2,"input":1,"textarea":1,"field-description":1}
--- light html.class= light
default: bg=oklch(0.205 0 0) color=oklch(0.985 0 0) h=36
secondary: bg=oklch(0.97 0 0) color=oklch(0.205 0 0) h=36
outline: bg=oklch(1 0 0) color=oklch(0.145 0 0) h=36
ghost: bg=rgba(0, 0, 0, 0) color=oklch(0.145 0 0) h=36
destructive: bg=oklch(0.577 0.245 27.325) color=rgb(255, 255, 255) h=36
link: bg=rgba(0, 0, 0, 0) color=oklch(0.205 0 0) h=36
ボタンの背景色は CSS の :root の値(--primary: oklch(0.205 0 0) など)と一致し、高さは h-9 の36px でした。ダイアログを開いて閉じたときの動きです。
--- dialog visible true | aria-labelledby -> 確認 / describedby -> この操作は取り消せません。
focus in dialog: true | active: BUTTON Close
portal parent: true
after Escape dialog count 0 | focus back: ダイアログを開く
ダイアログは body の直下に描かれ(ポータル)、開くとフォーカスがダイアログの中へ移り、Esc で閉じるとフォーカスが「ダイアログを開く」ボタンに戻りました。aria-labelledby はタイトルを、aria-describedby は説明文を指していました。このキーボード操作とアクセシビリティの属性は、Radix UI の Dialog が受け持つ部分です。 見た目のクラスだけが手元の dialog.tsx にあります。
components.jsonの設定項目
この節では、components.json の各項目の意味と、後から変えられない項目が分かります。
components.json は CLI がプロジェクトの形を知るための設定ファイルです。 公式ドキュメントは「CLI を使うときだけ必要で、コピー&ペーストで入れるなら無くてよい」としています。
| 項目 | 意味 | 後から変える |
|---|---|---|
style |
部品のスタイル(new-york、base-nova など) |
できない |
rsc |
React Server Components。true で "use client" を付ける |
できる |
tsx |
false で .jsx の JavaScript で入れる |
できる |
tailwind.config |
Tailwind v3 の設定ファイルの場所。v4 は空 | ― |
tailwind.css |
Tailwind を読み込む CSS ファイル | できる |
tailwind.baseColor |
色のもと(neutral・stone・zinc・mauve・olive・mist・taupe) | できない(migrate base-color で移行) |
tailwind.cssVariables |
true で CSS 変数、false で色のクラスを直書き |
できない(入れ直し) |
tailwind.prefix |
Tailwind のクラスの接頭辞(例 tw-) |
― |
aliases |
components・ui・lib・hooks・utils の置き場所 | できる |
iconLibrary |
lucide・tabler・hugeicons・phosphor・remixicon など | migrate icons |
registries |
追加のレジストリ(名前空間 @acme など) |
できる |
aliases の別名は、tsconfig.json の paths か、package.json の imports(#components/* の形。moduleResolution: "bundler" と resolvePackageJsonImports: true が要る)で解決させます。default スタイルは非推奨で、new-york か、2026年からの base-nova などを使います。
Tailwind CSS v4との関係(v3との違い)
この節では、shadcn/ui が Tailwind CSS v4 でどう動いていて、v3 のプロジェクトはどうなるかが分かります。
今の shadcn/ui は Tailwind CSS v4 と React 19 が前提です。 公式ドキュメントの Tailwind v4 のページにある変更点です。
| 変わったこと | v3 のころ | v4 の今 |
|---|---|---|
| 設定ファイル | tailwind.config.js に色を書く |
CSS の @theme inline に書く。tailwind.config は空 |
| 色の書き方 | HSL(0 0% 100%) |
OKLCH(oklch(1 0 0)) |
| アニメーション | tailwindcss-animate(プラグイン) |
tw-animate-css(CSS の import) |
| 部品の ref | React.forwardRef |
関数の props(React 19)。data-slot 属性つき |
| ボタンのカーソル | pointer | default(必要なら CSS か init --pointer) |
| 通知 | toast |
Radix 版は sonner。Base UI 版は新しい Toast |
既存の Tailwind v3・React 18 のアプリは、そのまま動き続けます。v3 用のドキュメントは v3.shadcn.com に残っています。v3 から上げるときは、Tailwind の公式のアップグレードガイドと codemod で Tailwind を上げ、CSS 変数を :root と .dark に出して @theme inline で参照する形に変えます。
cn パッケージの合成の仕組みは Tailwind v4 用です。公式の CLI のドキュメントは、Tailwind v3 のプロジェクトは tailwind-merge v2 を使い続けるよう書いています。Tailwind v4 の導入と、クラスが効かないときの切り分けは、関連記事「Tailwind CSS 使い方|v4の導入からつまずき対策まで実行結果つき」で扱っています。
shadcn/uiのテーマの変え方(CSS変数・色・角丸)
この節では、部品のコードを1行も変えずに色を変える方法と、新しい色を足す方法が、実際の色の値で分かります。
部品は bg-primary のような「役割の名前」の色を使い、その中身は CSS 変数で決まります。 変数を変えれば、その色を使う部品が全部変わります。
flowchart TD
A[CSS の root の<br>primary 変数] --> B[theme inline の<br>color-primary]
B --> C[Tailwind の<br>bg-primary]
C --> D[Button の<br>default]
C --> E[Badge・リンク<br>など]
| 変数(背景/文字) | 何の色か | 使う部品 |
|---|---|---|
background / foreground |
ページの背景と文字 | ページ全体 |
card / card-foreground |
浮いた面 | Card・パネル |
popover / popover-foreground |
重なって出る面 | Popover・DropdownMenu |
primary / primary-foreground |
主な操作 | Button の default・Badge |
secondary / secondary-foreground |
控えめな操作 | Button の secondary |
muted / muted-foreground |
目立たない面と説明文 | 説明・プレースホルダー |
accent / accent-foreground |
ホバー・選択中 | ghost のボタン・メニュー |
destructive |
削除・エラー | destructive のボタン |
border・input・ring |
枠線・入力欄の枠・フォーカスの輪 | ほぼ全部 |
chart-1〜chart-5 |
グラフの色 | Chart |
sidebar-* |
サイドバーの色 | Sidebar |
radius |
角丸の基準 | radius-sm〜radius-4xl を計算 |
名前の決まりは「背景の色」と「その上の文字の色(-foreground)」の組です。bg-primary text-primary-foreground と書くと、背景は var(--primary)、文字は var(--primary-foreground) になります。
主な色を変え、新しい色(warning)を足した例
手元のプロジェクトで、:root の --primary を青に変え、公式の「Adding New Tokens」の手順で warning の色を足し、Button に warning の種類を1行足しました。
/* src/index.css(変えた・足したところ) */
@theme inline {
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
/* ……既存の行 */
}
:root {
--warning: oklch(0.84 0.16 84);
--warning-foreground: oklch(0.28 0.07 46);
--primary: oklch(0.488 0.217 264); /* 元は oklch(0.205 0 0) */
}
.dark {
--warning: oklch(0.41 0.11 46);
--warning-foreground: oklch(0.99 0.02 95);
}
// src/components/ui/button.tsx の variant に1行足す
warning: "bg-warning text-warning-foreground hover:bg-warning/90",
ビルドして、ライトとダークで測った色です。
light default: bg=oklch(0.488 0.217 264) color=oklch(0.985 0 0)
light link: bg=rgba(0, 0, 0, 0) color=oklch(0.488 0.217 264)
light warning: bg=oklch(0.84 0.16 84) color=oklch(0.28 0.07 46)
dark default: bg=oklch(0.922 0 0) color=oklch(0.205 0 0)
dark link: bg=rgba(0, 0, 0, 0) color=oklch(0.922 0 0)
dark warning: bg=oklch(0.41 0.11 46) color=oklch(0.99 0.02 95)
--primary を1か所変えただけで、default のボタンと link の文字の色の両方が青になりました。ダークでは .dark の --primary が使われるので、元の色のままです。ダークでも色を変えたいときは、.dark の側も書き換えます。 ビルド後の CSS には bg-warning{background-color:var(--warning)} が出力されていました。
角丸は --radius 1つで決まり、--radius-sm は calc(var(--radius) * 0.6)、--radius-xl は calc(var(--radius) * 1.4) のように計算されます。--radius: 0.625rem を変えると、全部の部品の角丸が同じ割合で変わります。配色・フォント・角丸をまとめて見ながら選ぶなら shadcn/create でプリセットを作り、既存のプロジェクトには npx shadcn@latest apply <コード>(--only theme で色だけ)で当てます。CSS 変数そのものの書き方は、関連記事「CSS変数(カスタムプロパティ)の使い方|コピペ実例とダークモード切替」で扱っています。
shadcn/uiのダークモード(Vite・Next.js)
この節では、ダークモードの仕組みと、Vite・Next.js それぞれの書き方が、切り替えた実物で分かります。
ダークモードは、<html> に dark クラスを付けると .dark の CSS 変数が使われる仕組みです。 CSS の @custom-variant dark (&:is(.dark *)); で、Tailwind の dark: も同じクラスで動きます。
Vite(自作のThemeProvider)
公式の Vite のダークモードの手順は、localStorage に選んだテーマを保存し、<html> のクラスを付け替える ThemeProvider(約70行)と、Light・Dark・System を選ぶ ModeToggle(DropdownMenu を使う)を置く形です。
// src/App.tsx(抜粋)
import { ThemeProvider } from "@/components/theme-provider"
import { ModeToggle } from "@/components/mode-toggle"
function App() {
return (
<ThemeProvider defaultTheme="light" storageKey="vite-ui-theme">
<header className="flex items-center justify-between">
<h1 className="text-2xl font-bold">shadcn/ui のデモ</h1>
<ModeToggle />
</header>
{/* …… */}
</ThemeProvider>
)
}
ModeToggle を押して Dark を選び、ページを読み直した結果です。
menu items [ 'Light', 'Dark', 'System' ]
--- dark html.class= dark localStorage dark
body bg oklch(0.145 0 0)
after reload html.class= dark
system + OS dark → html.class= dark
選んだテーマは localStorage の vite-ui-theme に保存され、読み直しても dark のままでした。System を選んだ状態で OS(ブラウザ)の設定がダークだと、dark が付きました。ダークで測ったボタンの色は、default が oklch(0.922 0 0)、secondary が oklch(0.269 0 0) で、.dark の変数の値と一致しました。
この ThemeProvider は、React が描画された後(useEffect)にクラスを付けます。手元の測定では、読み込み直後のしばらくの間はボタンの色がライトからダークへ移り変わる途中の値でした(ボタンに transition-all が付いているため)。
Next.js(next-themes)
Next.js では next-themes を使います。<html> に suppressHydrationWarning を付け、attribute="class" で dark クラスを付けさせます。
npm install next-themes
// components/theme-provider.tsx
"use client"
import * as React from "react"
import { ThemeProvider as NextThemesProvider } from "next-themes"
export function ThemeProvider({
children,
...props
}: React.ComponentProps<typeof NextThemesProvider>) {
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
}
// app/layout.tsx
import { ThemeProvider } from "@/components/theme-provider"
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja" suppressHydrationWarning>
<body>
<ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
{children}
</ThemeProvider>
</body>
</html>
)
}
disableTransitionOnChange は、切り替えの瞬間だけ CSS のトランジションを止める設定です。公式ドキュメントには Astro・Remix・TanStack Start のダークモードの手順もあります。
shadcn/uiのコンポーネント早見表
この節では、よく使う部品の名前と用途、Base UI 版・Radix 版の違いがある部品を引けます。
公式ドキュメントの部品のページは、2026年10月22日時点で Base UI 版66・Radix 版67・React Aria 版65です。入れるコマンドはどれも npx shadcn@latest add 名前 です。
| 用途 | 部品の名前(add に書く名前) | メモ |
|---|---|---|
| ボタン | button・button-group・toggle・toggle-group |
variant 6種・size 8種 |
| 入力 | input・textarea・select・native-select・checkbox・radio-group・switch・slider |
フォームは field と組む |
| フォーム | field・label・input-group・input-otp |
以前の form に代わる組み方 |
| 選ぶ・探す | combobox・command・calendar・date-picker |
command はコマンドパレット |
| 表示 | card・badge・avatar・table・data-table・chart・skeleton・empty・kbd |
skeleton は読み込み中の仮表示 |
| 重なって出る | dialog・alert-dialog・sheet・drawer・popover・tooltip・hover-card |
フォーカスの管理つき |
| メニュー | dropdown-menu・context-menu・menubar・navigation-menu |
React Aria 版に menubar は無い |
| 画面の骨組み | sidebar・tabs・accordion・collapsible・resizable・scroll-area・breadcrumb・pagination |
sidebar はブロックでも使う |
| 通知 | alert・toast(Base UI)・sonner(Radix・Aria) |
Radix の toast は非推奨 |
| 状態 | progress・spinner |
ボタンの中にも置ける |
| AI・チャット | message・bubble・attachment・code-block・questionnaire |
2026年に追加 |
部品の組み合わせ(ログイン画面・ダッシュボード・サイドバー)をまとめて入れる「ブロック」もあります。npx shadcn@latest add login-01 のように入れると、ブロックが使う button・label・input・card も一緒に入ります。グラフは chart(Recharts を使う部品)を入れ、色は CSS 変数の --chart-1〜--chart-5 を使います。
Radix UI・Base UI・React Ariaの違いと選び方
この節では、3つのベース(部品の動きを受け持つライブラリ)の違いと、書き方で変わる点が分かります。
2026年7月2日から、init で作る新しいプロジェクトの既定は Base UI です。 Radix UI は非推奨ではなく、新しい部品も両方に出る、と公式の変更履歴は書いています。React Aria は2026年7月17日に加わりました。
| ベース | npm のパッケージ | 位置づけ(2026年10月22日時点) |
|---|---|---|
| Base UI | @base-ui/react(1.9.0) |
新規の既定。init でそのまま選ばれる |
| Radix UI | radix-ui(1.8.1) |
引き続き対応。init -b radix |
| React Aria | react-aria-components(1.22.1) |
init --base aria |
Radix 版の書き方
別の要素として描くときは asChild
<DialogTrigger asChild><Button variant="outline">開く</Button></DialogTrigger>
通知は sonner
Base UI 版の書き方
別の要素として描くときは render
<DialogTrigger render={<Button variant="outline" />}>開く</DialogTrigger>
通知は新しい toast
使い方(<Dialog> の中に <DialogTrigger>・<DialogContent> を置く形)は、どのベースでも同じです。変わるのは、上のように「子の要素として描く」ときの書き方や、一部のプロパティです。公式は、Base UI 版の Button を render={<a />} でリンクにすると role="button" が付くので、リンクには buttonVariants を普通の <a> に付ける形を案内しています。
| 状況 | 選ぶもの |
|---|---|
| これから新しく作る | Base UI(既定。公式もすすめている) |
| すでに Radix 版で動いている | そのまま Radix(公式は移行は不要としている) |
解説記事・社内のコードが asChild で書かれている |
Radix にそろえると読み替えが要らない |
| React Aria のアクセシビリティの仕組みを使いたい | React Aria |
| Radix から Base UI へ少しずつ移したい | 公式の skill(npx skills add shadcn/ui)で1部品ずつ |
この記事の手動導入で new-york-v4(Radix 版)を使ったのは、Tailwind のクラスが入った形のソースが GitHub にそのまま置かれているためです。Base UI 版を CLI で入れると components.json の style は base-nova などになります。
shadcn/uiでフォームを作る(React Hook Form+zod)
この節では、Field の部品と React Hook Form・zod で入力チェック付きのフォームを作る書き方と、エラーが表示される様子が分かります。
今の shadcn/ui のフォームは、<Field> の部品と React Hook Form の <Controller> を組み合わせて作ります。 公式ドキュメントのフォームのページは React Hook Form・TanStack Form・Formisch の3つの書き方を載せていて、部品の一覧に以前の form はありません。
入れるもの
npm install react-hook-form @hookform/resolvers zod
2026年10月22日時点、npm 10.9.7 で(空のプロジェクトでも)このコマンドを実行すると、@hookform/resolvers 6.0.0(2026年10月19日公開)の任意の依存の組み合わせで次のエラーになりました。
npm error code ERESOLVE
npm error ERESOLVE unable to resolve dependency tree
npm error
npm error While resolving: t1@1.0.0
npm error Found: effect@3.22.3
npm error node_modules/effect
npm error peerOptional effect@"^3.6.5" from @typeschema/effect@0.14.0
...
npm error Could not resolve dependency:
npm error peerOptional effect@"^4.0.0" from @hookform/resolvers@6.0.0
| やり方 | 結果(手元) |
|---|---|
| npm 11.21.1 で同じコマンド | エラーなく入った |
npm 10.9.7 で --legacy-peer-deps を付ける |
入った(この記事のプロジェクト) |
npm 10.9.7 で @hookform/resolvers@5.8.0 を指定 |
入った(5.9.0 以降は同じエラー) |
フォームのコード
メールアドレスとお問い合わせ内容を受ける例です。公式の例(form-rhf-demo)と同じ組み方で、メッセージを日本語にしました。
// src/components/contact-form.tsx
import { zodResolver } from "@hookform/resolvers/zod"
import { Controller, useForm } from "react-hook-form"
import * as z from "zod"
import { Button } from "@/components/ui/button"
import { Field, FieldDescription, FieldError, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
const formSchema = z.object({
email: z.email("メールアドレスの形式で入力します。"),
message: z
.string()
.min(10, "お問い合わせ内容は10文字以上で入力します。")
.max(200, "お問い合わせ内容は200文字以内で入力します。"),
})
type FormValues = z.infer<typeof formSchema>
export function ContactForm({ onDone }: { onDone: (v: FormValues) => void }) {
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: { email: "", message: "" },
})
return (
<form id="contact" onSubmit={form.handleSubmit(onDone)} noValidate>
<FieldGroup>
<Controller
name="email"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor="contact-email">メールアドレス</FieldLabel>
<Input {...field} id="contact-email" type="email" aria-invalid={fieldState.invalid} />
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Controller
name="message"
control={form.control}
render={({ field, fieldState }) => (
<Field data-invalid={fieldState.invalid}>
<FieldLabel htmlFor="contact-message">お問い合わせ内容</FieldLabel>
<Textarea {...field} id="contact-message" aria-invalid={fieldState.invalid} />
<FieldDescription>{field.value.length}/200 文字</FieldDescription>
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
</Field>
)}
/>
<Button type="submit">送信</Button>
</FieldGroup>
</form>
)
}
ポイントは3つです。<Field> に data-invalid、入力の部品に aria-invalid を付けると、エラーのときの赤い枠などの見た目になります。<FieldError> に zod のエラーを渡すとメッセージが出ます。noValidate はブラウザ自体の入力チェックを止めて、zod のチェックだけを見せるために付けています(公式の例の注記と同じ考え方)。
送信してエラーが出る様子
空のまま送信 → 形の違う値で送信 → 正しい値を入れて送信、の順に操作した結果です。
--- empty submit errors: ["メールアドレスの形式で入力します。","お問い合わせ内容は10文字以上で入力します。"]
aria-invalid: contact-email=true contact-message=true
field data-invalid: 2
error role: alert,alert
--- bad values errors: ["メールアドレスの形式で入力します。","お問い合わせ内容は10文字以上で入力します。"]
after typing (onSubmit mode) errors: []
--- sent: {"email":"taro@example.com","message":"shadcn/ui の導入について相談したいです。"} | errors: 0
counter: 25/200 文字
エラーの文は role="alert" の要素に入るので、スクリーンリーダーにも読まれます。taro@example は zod の z.email() でエラーになりました。一度送信した後は、正しい値を入れた時点でエラーが消えました(React Hook Form は既定で、送信の後は入力のたびにチェックし直します)。チェックのタイミングは useForm の mode(onSubmit・onBlur・onChange・onTouched・all)で変えられます。React Hook Form と zod v4 の書き方の詳細は、関連記事「React Hook Formの使い方|zod v4連携のコピペ例とエラー対処」で扱っています。
shadcn CLIのコマンド一覧(init・add・view・migrate など)
この節では、CLI 4.22.1 のコマンドを一覧で引けます。npx shadcn --help で出た一覧と、公式ドキュメントの説明を合わせました。
Commands:
init|create [options] [components...] initialize your project and install dependencies
apply [options] [preset] apply a preset to an existing project
add [options] [components...] add a component to your project
diff [options] [component] [DEPRECATED] Use `add [component] --diff` instead.
docs [options] <components...> get docs, api references and usage examples for components
view [options] <items...> view items from the registry
search|list [options] [registries...] search items from registries
migrate [options] [migration] [path] run a migration.
eject [options] inline shadcn/tailwind.css and remove the shadcn dependency
info [options] get information about your project
build [options] [registry] build components for a shadcn registry
mcp [options] MCP server and configuration commands
preset manage presets
registry manage registries
| コマンド | 何をするか | 例 |
|---|---|---|
init |
設定・依存・CSS 変数を用意する | npx shadcn@latest init -t vite |
add |
部品を足す | add dialog、add --all |
view |
入れる前に中身を見る | view button card |
search |
レジストリを探す | search @shadcn -q "button" |
docs |
部品のドキュメントを取る | docs dialog |
apply |
プリセットを既存のプロジェクトに当てる | apply <コード> --only theme |
migrate |
移行(cn・icons・base-color・radix・rtl) | migrate cn |
eject |
shadcn/tailwind.css を CSS に書き出し、依存を外す |
eject |
info |
プロジェクトの情報を出す | info --json |
build |
自分のレジストリの JSON を作る | build(public/r に出力) |
mcp |
MCP サーバーとして動かす・設定する | mcp init --client claude |
migrate --list は手元でも動き、使える移行の一覧が出ました。
Available migrations:
- cn: migrate clsx and tailwind-merge to cn.
- icons: migrate your ui components to a different icon library.
- base-color: migrate your theme to a different base color.
- radix: migrate to radix-ui.
- rtl: migrate your components to support RTL (right-to-left).
migrate cn は、clsx と tailwind-merge で書いた cn 関数を export { cn } from "cn" に置き換え、使われなくなったパッケージを外します。
部品の更新とカスタマイズの管理
部品は自分のコードなので、上流の変更は自動では入りません。取り込むときは、先に自分の変更をコミットし、--diff で見比べます。
git add . && git commit -m "部品の変更を保存"
npx shadcn@latest add button --diff # 上流との差分を見る
npx shadcn@latest add button --overwrite # 上書きしてから、自分の変更を戻す
- 1部品を自分で直した箇所が分かるか変更はコミットを分けておくと、上書きの後に戻しやすい
- 2見た目の変更は CSS 変数でできないか色・角丸は部品を触らず CSS で変えると、更新の衝突が減る
- 3新しい見た目は variant を足して作ったか既存のクラスを書き換えるより、1行足すほうが差分が小さい
- 4動きの部分の更新は npm で入るかradix-ui・@base-ui/react の版を上げると、フォーカスなどの修正が入る
- 5CI で init を自動で動かしていないか既定が Base UI に変わったので、Radix のままなら -b radix を足す
MUI・Chakra UIとの違い
この節では、npm で入れる UI ライブラリとの違いを、各公式の情報で比べられます。
| 比べる点 | shadcn/ui | MUI(Material UI) | Chakra UI |
|---|---|---|---|
| 入れ方 | CLI でソースを書き込む | npm install @mui/material @emotion/react @emotion/styled |
npm i @chakra-ui/react @emotion/react |
| 部品のコードの場所 | 自分のプロジェクト | node_modules | node_modules(snippets CLI で一部をコピーできる) |
| 見た目の付け方 | Tailwind CSS のクラス+CSS 変数 | 既定は Emotion | Emotion(実行時) |
| 動きの部分 | Base UI・Radix・React Aria | ライブラリの中 | Ark UI(依存) |
| 版(npm、2026年10月22日時点) | shadcn 4.22.1(CLI) | 9.5.0 | 3.37.0 |
| ライセンス | MIT | MIT | MIT |
Chakra UI にも npx @chakra-ui/cli snippet add で部品をプロジェクトにコピーする仕組みがあります。daisyUI は Tailwind CSS のプラグインとして npm i -D daisyui@latest で入れ、CSS に @plugin "daisyui"; を書く形です。
| 状況 | 選びやすいもの |
|---|---|
| Tailwind CSS で作っていて、部品のコードも自分で持ちたい | shadcn/ui |
| Material Design の見た目と、多くの既製の部品を npm の更新で受けたい | MUI |
| Tailwind を使わず、Emotion のスタイルで組みたい | Chakra UI |
| JavaScript の部品は要らず、Tailwind のクラスで見た目だけそろえたい | daisyUI |
| v0 などの AI で作った画面をそのまま育てたい | shadcn/ui(v0 の出力が shadcn/ui の構成) |
shadcn/ui を選ぶと、部品の更新を取り込む作業は自分たちの仕事になります。部品を多く直すほど、上流との差分の管理が増えます。
AI・v0・MCPとshadcn/uiの連携
この節では、AI のコーディングツールから shadcn/ui を使う仕組みが分かります。
Vercel の v0 は、Next.js と shadcn/ui の構成でコードを出力します。 v0 で作った画面を手元に持ってくると、components/ui/ に shadcn/ui の部品が入った形になります。v0 の使い方と、出力を手元でビルドする手順は、新規記事「v0とは|使い方・料金・ローカルで動かす手順をNext.jsで実演」で扱っています。
CLI は MCP サーバーとしても動き、Claude Code・Cursor・VS Code・Codex・OpenCode から「部品を探す」「足す」を頼めます。Claude Code なら、プロジェクトで次を実行します(公式ドキュメント)。
npx shadcn@latest mcp init --client claude
手で書く場合の .mcp.json です。
{
"mcpServers": {
"shadcn": {
"command": "npx",
"args": ["shadcn@latest", "mcp"]
}
}
}
ほかに、コーディングエージェントに shadcn/ui の書き方(Radix と Base UI の API の違い・CLI のフラグなど)を教える skill(npx skills add shadcn/ui)もあります。.mcp.json の置き場所と書き方は、関連記事「Claude Code MCP設定の追加方法|.mcp.json雛形と一覧」で扱っています。
社内の部品を配る(レジストリ)
components.json の registries に名前空間を書くと、自分たちのレジストリから add できます。GitHub のリポジトリの直下に registry.json を置くと、そのリポジトリ自体がレジストリになります(2026年6月から)。
{
"registries": {
"@acme": "https://registry.acme.com/{name}.json"
}
}
npx shadcn@latest add @acme/login-form
npx shadcn@latest add <username>/<repo>/<item> # GitHub のリポジトリから
npx shadcn@latest build # registry.json から JSON を作る
shadcn/uiのよくあるエラーと直し方
この節では、導入から部品を足すまでに出るエラー文から、原因と直し方を引けます。すべて手元で実際に出た文です。
エラーの早見表
| エラー文・症状 | 原因 | 直し方 |
|---|---|---|
error TS5101: Option 'baseUrl' is deprecated |
TypeScript 6 で baseUrl が非推奨 |
baseUrl の行を消す(paths は残す) |
Failed to resolve import "@/components/..." |
Vite に @ の別名が無い |
resolve.alias か resolve.tsconfigPaths: true |
[UNLOADABLE_DEPENDENCY] Could not load src/components/ui/select |
部品のファイルが無い | add select か、ソースを置く |
Rolldown failed to resolve import "next-themes" |
部品が使うパッケージが無い | Manual のタブにあるパッケージを入れる |
Type '"primary"' is not assignable to type ... |
variant に無い名前 | buttonVariants に1行足すか、既存の名前に |
Request to https://ui.shadcn.com/... failed |
CLI がレジストリに届かない | 通信を許可するか、手動導入 |
npm error ERESOLVE unable to resolve dependency tree |
@hookform/resolvers 6.0.0 と npm 10 | npm 11 か --legacy-peer-deps |
| 部品に色も枠も付かない | CSS 変数と @theme inline が無い |
Manual の CSS を貼る |
npx shadcn-ui が動かない |
以前のパッケージ名(非推奨) | npx shadcn@latest |
Failed to resolve import "@/components/..."(devだけ止まる)
vite.config.ts の resolve.alias を消して開発サーバー(npx vite)を起動すると、次のエラーでページが表示されませんでした。
(!) Failed to run dependency scan. Skipping dependency pre-bundling. Error: The following dependencies are imported but could not be resolved:
@/components/contact-form (imported by …/src/App.tsx)
@/components/ui/button (imported by …/src/App.tsx)
...
Are they installed?
[vite] (client) Pre-transform error: Failed to resolve import "@/components/contact-form" from "src/App.tsx". Does the file exist?
Plugin: vite:import-analysis
同じ設定で vite build は通りました。 Vite 8.3.5 では、本番のビルドと開発サーバーで @ の解決のされ方が違いました。ビルドだけで確かめていると見落とすので、npm run dev でも開いて確かめます。直し方は、公式の手順どおり resolve.alias を書くか、resolve: { tsconfigPaths: true } を書くかです。
Could not load src/components/ui/select(部品のファイルが無い)
置いていない部品(select)を import して vite build したときです。
✗ Build failed in 434ms
error during build:
Build failed with 1 error:
[UNLOADABLE_DEPENDENCY] Could not load src/components/ui/select
╭─[ src/App.tsx:1:23 ]
1 │ import { Label } from "@/components/ui/select";
│ ────────────┬───────────
│ ╰───────────── No such file or directory (os error 2)
v0 や解説記事のコードを貼ったときによく起きます。npx shadcn@latest add select で足すか、手動ならソースを置きます。
Rolldown failed to resolve import(部品が使うパッケージが無い)
sonner.tsx(通知の部品)だけを置き、sonner と next-themes を入れずにビルドしたときです。
Error: [vite]: Rolldown failed to resolve import "next-themes" from "…/src/components/ui/sonner.tsx".
This is most likely unintended because it can break your application at runtime.
If you do want to externalize this module explicitly add it to
`build.rolldownOptions.external`
型チェック(tsc -b)では、同じ原因が次の形で出ました。
src/components/ui/sonner.tsx(10,26): error TS2307: Cannot find module 'next-themes' or its corresponding type declarations.
src/components/ui/sonner.tsx(11,54): error TS2307: Cannot find module 'sonner' or its corresponding type declarations.
CLI の add なら依存も一緒に入りますが、手で置くときは、部品のページの Manual のタブにある npm install … も実行します。部品のファイルの先頭の import を見ると、何が要るかが分かります。
Type '"primary"' is not assignable(variantの名前の間違い)
src/App.tsx(42,21): error TS2322: Type '"primary"' is not assignable to type '"default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined'.
<Button variant="primary"> と書いたときです。shadcn/ui の Button の主な色は default で、primary という種類はありません。型のエラーに、使える名前が全部出ます。新しい種類が欲しいときは、テーマの節の warning のように buttonVariants に足します。
部品に色も枠も付かない
src/index.css を Tailwind の1行(@import "tailwindcss";)だけにしてビルドすると、エラーは出ず、ボタンの色が付きませんでした。
default: bg=rgba(0, 0, 0, 0) color=rgb(0, 0, 0) border=0px
secondary: bg=rgba(0, 0, 0, 0) color=rgb(0, 0, 0) border=0px
outline: bg=rgba(0, 0, 0, 0) color=rgb(0, 0, 0) border=1px
bg-primary は @theme inline の --color-primary が無いとクラスとして作られず、--primary が無いと色の値もありません。Vite の手順で index.css を1行にした後に init を実行していないと、この状態になります。init を実行するか、Manual の CSS を貼ります。
よくある質問
Q. shadcn/uiとは簡単に言うと何ですか? A. ボタンやダイアログなどの React の部品を、ソースコードのまま自分のプロジェクトにコピーして使う部品集です。見た目は Tailwind CSS、動きは Base UI・Radix UI・React Aria が受け持ちます。
Q. shadcnの読み方と、shadcnとshadcn/uiの違いは?
A. shadcn は作者のハンドル名で、CLI の npm パッケージ名も shadcn です。プロジェクト(部品集)の名前が shadcn/ui です。公式ドキュメント(GitHub のドキュメントのソース)には、読み方の記載はありません(2026年10月22日時点)。
Q. shadcn/uiは無料ですか?商用利用できますか? A. MIT ライセンスで無料です。商用のアプリにも使えます。土台の Radix UI・Base UI も MIT、React Aria Components は Apache-2.0 です(2026年10月22日時点、npm の表示)。
Q. npm installで入れられないのですか?
A. 部品そのものは npm のパッケージではなく、CLI(npx shadcn@latest add)か手動で、ソースをプロジェクトに書き込みます。部品が使う radix-ui・cn などのパッケージは npm で入ります。
Q. ViteとNext.jsのどちらでも使えますか?
A. 使えます。init -t vite・init -t next のほか、React Router・Astro・Laravel・TanStack Start のテンプレートと手順があります。公式のドキュメントは React 向けです。
Q. Tailwind CSS v3でも使えますか? A. 既存の v3 のプロジェクトは動き続けますが、今の部品とドキュメントは Tailwind v4 が前提です。v3 用のドキュメントは v3.shadcn.com にあります。
Q. Radix UIとBase UIのどちらを選べばよいですか?
A. 2026年7月から新規の既定は Base UI で、公式もすすめています。すでに Radix 版で動いているなら、公式は移行は不要としています。書き方の違いは主に asChild(Radix)と render(Base UI)です。
Q. Formコンポーネントが見つかりません。
A. 今のドキュメントでは、フォームは field の部品と React Hook Form の Controller(または TanStack Form など)で組みます。この記事のフォームの節に、動かしたコードとエラー表示の実物があります。
Q. shadcnのCLIでエラーになり部品を追加できません。
A. Request to https://ui.shadcn.com/... failed なら、レジストリへの通信が通っていません。通信を許可するか、公式の Manual の手順で、GitHub のソースを手で置きます(この記事で全手順を実行しています)。
Q. ダークモードはどう設定しますか?
A. <html> に dark クラスが付くと .dark の CSS 変数が使われます。Vite は ThemeProvider を自作し、Next.js は next-themes を使います。
Q. 部品をアップデートするには?
A. 自分の変更をコミットしてから、npx shadcn@latest add button --diff で上流との差分を見て取り込みます。上書きするなら --overwrite です。
まとめ
- shadcn/ui は、部品のソースを
components/ui/に書き込んで使う React の部品集。見た目は Tailwind のクラス、動きは Base UI・Radix UI・React Aria。MIT で無料。 - 入れ方は
npx shadcn@latest init(-t next・-t vite)とadd。2026年7月から新規の既定は Base UI、Radix は-b radix。CLI は 4.22.1(2026年10月22日時点)。 - CLI がレジストリに届かないときは、Manual の手順(依存5つ・
@の別名・CSS・cn)と GitHub の new-york-v4 のソースで動く。import のパスを@/components/ui/に直す。 - TypeScript 6(create-vite 9.3.1)では、公式の手順の
baseUrlが TS5101 のエラーになる。pathsだけにする。Vite 8 はaliasが無いと build は通って dev だけ止まる。 - 色は CSS 変数(
:rootと.dark)で変える。新しい色は:root・.dark・@theme inlineに足し、variant を1行足す。 - フォームは
Field+React Hook Form のController+zod。npm 10 で @hookform/resolvers 6.0.0 が ERESOLVE になるときは npm 11 か--legacy-peer-deps。 - 部品は自分のコードなので、更新は
--diffで見比べて取り込む。
参考・出典
確認日はいずれも 2026年10月22日です。
- shadcn/ui「Introduction」:https://ui.shadcn.com/docs
- shadcn/ui「Vite」:https://ui.shadcn.com/docs/installation/vite
- shadcn/ui「Next.js」:https://ui.shadcn.com/docs/installation/next
- shadcn/ui「Manual Installation」:https://ui.shadcn.com/docs/installation/manual
- shadcn/ui「shadcn」(CLI):https://ui.shadcn.com/docs/cli
- shadcn/ui「components.json」:https://ui.shadcn.com/docs/components-json
- shadcn/ui「Theming」:https://ui.shadcn.com/docs/theming
- shadcn/ui「Tailwind v4」:https://ui.shadcn.com/docs/tailwind-v4
- shadcn/ui「Dark Mode」(Vite・Next.js):https://ui.shadcn.com/docs/dark-mode/vite
- shadcn/ui「React Hook Form」:https://ui.shadcn.com/docs/forms/react-hook-form
- shadcn/ui「MCP Server」:https://ui.shadcn.com/docs/mcp
- shadcn/ui「GitHub Registries」:https://ui.shadcn.com/docs/registry/github
- shadcn/ui「Changelog」(Base UI as the Default・React Aria・cn・CLI v4・Unified Radix UI Package):https://ui.shadcn.com/docs/changelog
- shadcn-ui/ui(GitHub。apps/v4/content/docs・apps/v4/registry):https://github.com/shadcn-ui/ui
- npm「shadcn」:https://www.npmjs.com/package/shadcn
- npm「cn」:https://www.npmjs.com/package/cn
- TypeScript「TypeScript 6.0 migration」(エラー文の案内先):https://aka.ms/ts6
- Vite「Shared Options(resolve.alias など)」:https://vite.dev/config/shared-options
- MUI「Installation」:https://mui.com/material-ui/getting-started/installation/
- Chakra UI「Installation」:https://chakra-ui.com/docs/get-started/installation
- daisyUI「Install」:https://daisyui.com/docs/install/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「shadcn/uiとは|使い方・導入手順とエラーの直し方をViteで実演」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。