はい、承知いたしました。React/Next.js開発者向けに、shadcn/uiを使ったUI開発に関する詳細な解説記事(約5000語)を執筆します。記事を直接ここに表示します。
React/Next.js開発必見!shadcn/uiで美しいUIを爆速実装
はじめに:UI開発の課題と新たな潮流
現代のウェブアプリケーション開発において、ユーザーインターフェース(UI)はユーザー体験を左右する最も重要な要素の一つです。ReactやNext.jsといったフレームワークを用いた開発では、コンポーネント指向の設計思想に基づき、再利用可能で保守性の高いUIを構築することが一般的となっています。
これまで、多くのReact/Next.js開発者は、UI開発の効率化と品質向上のために様々なUIコンポーネントライブラリを利用してきました。代表的なものとしては、Material UI、Ant Design、Chakra UI、React Bootstrapなどがあります。これらのライブラリは、ボタン、入力フォーム、モーダル、ナビゲーションといった基本的なUIコンポーネントを豊富に提供しており、デザインの一貫性を保ちながら開発スピードを向上させるのに役立ちます。
しかし、これらの伝統的なUIライブラリには、いくつかの課題が存在することも事実です。
- カスタマイズ性の限界: 提供されるコンポーネントは高度に抽象化されているため、細かいデザインや挙動のカスタマイズが難しい場合があります。デフォルトのスタイルを上書きしようとすると、複雑なCSSセレクタやスタイルプロパティが必要になり、予期しない副作用が発生することもあります。
- 依存関係とバンドルサイズ: ライブラリ全体をインストールするため、使用しないコンポーネントやスタイルも含まれてしまい、結果としてアプリケーションのバンドルサイズが増加する傾向があります。これは特にパフォーマンスが重視されるモダンなウェブアプリケーションでは看過できない問題です。
- 抽象化による学習コスト: ライブラリ独自のAPIやスタイルシステムを理解する必要があります。また、内部の実装がブラックボックス化されているため、期待通りの挙動をしない場合にデバッグが困難になることがあります。
- スタイリング手法の制約: 多くのライブラリは特定のスタイリングソリューション(CSS-in-JSや独自のCSSフレームワーク)に依存しており、Tailwind CSSのようなユーティリティファーストなCSSフレームワークとの併用が難しい、あるいは工夫が必要な場合があります。
これらの課題に対し、近年新たなアプローチが登場しています。その一つが、今回ご紹介するshadcn/ui
です。shadcn/ui
は、従来のUIライブラリとは一線を画す独自の哲学に基づいて設計されており、React/Next.js開発におけるUI実装のワークフローに革新をもたらしています。
この記事では、shadcn/ui
がなぜこれほど注目されているのか、その哲学と特徴から、実際の導入方法、主要コンポーネントの使い方、そして最大の魅力であるカスタマイズ方法までを、約5000語の大ボリュームで徹底的に解説します。これを読めば、あなたもshadcn/ui
を使って、美しく、かつ高速なUI実装を実現できるようになるでしょう。
shadcn/uiの哲学と特徴:ライブラリではない、コンポーネントの「コレクション」
shadcn/ui
を理解する上で最も重要な点は、「これはUIコンポーネントライブラリではない」と作者自身が言及していることです。では、一体何なのでしょうか?
shadcn/ui
は、正確には「美しく、カスタマイズ可能で、アクセシブルなコンポーネントの集まり(Collection)」です。これはどういう意味かというと、npmなどのパッケージマネージャーを使ってライブラリ全体を依存関係に追加するのではなく、必要なコンポーネントのコードを直接自分のプロジェクトにコピー&ペーストする形で利用するというユニークな配布方法をとっているということです。
この「コピペ」アプローチには、従来のライブラリにはない明確な利点があります。
- 究極のカスタマイズ性: プロジェクトにコピーされたコンポーネントは、あなたのプロジェクトの一部となります。つまり、必要に応じてそのコードを自由に編集・修正できます。デザインの微調整はもちろん、機能の追加や変更も容易に行えます。これは、UIライブラリのブラックボックス化されたコンポーネントでは不可能だったレベルの柔軟性を提供します。
- 不要なコードを含まない: 必要なコンポーネントだけをプロジェクトに追加するため、未使用のコンポーネントがバンドルサイズを圧迫することはありません。アプリケーションは必要なコードのみで構成され、パフォーマンスへの影響を最小限に抑えることができます。
- 依存関係の削減:
shadcn/ui
自体を依存関係として追加しないため、依存関係ツリーがシンプルになります。コンポーネントごとに必要最低限の依存ライブラリ(主にRadix UI)が追加されますが、ライブラリ全体を導入するよりはるかに軽量です。 - コードの可視性: コンポーネントの実装コードが手元にあるため、内部で何が行われているのかを確認できます。これはデバッグ時だけでなく、高品質なコンポーネントの設計を学ぶ上でも非常に役立ちます。
- Tailwind CSSとの親和性:
shadcn/ui
のコンポーネントは、スタイリングにTailwind CSSを使用することを前提として設計されています。Tailwind CSSのユーティリティクラスが多用されており、既存のTailwind CSSプロジェクトにスムーズに統合できます。また、Tailwind Variants (cva
) というライブラリを使用して、Variantシステム(ボタンのPrimary/Secondaryなど)を管理しており、これもTailwind CSSユーザーには馴染みやすいでしょう。 - Radix UIによるアクセシビリティと品質:
shadcn/ui
の多くのコンポーネントは、ヘッドレスUIライブラリであるRadix UIの上に構築されています。Radix UIは、アクセシビリティ、キーボード操作、状態管理など、UIコンポーネントの基盤となる複雑な部分を高品質に実装して提供しています。shadcn/ui
はRadix UIの堅牢な基盤を利用しつつ、Tailwind CSSで美しいスタイルを適用しています。これにより、見た目の美しさだけでなく、高いアクセシビリティと安定した挙動が保証されます。
shadcn/uiの背後にある技術スタック
- React: コンポーネントモデルの基盤。
- Next.js: 公式ドキュメントや多くのチュートリアルで利用されており、特にApp RouterやServer Componentsとの連携が考慮されています。
- TypeScript: 型安全な開発をサポート。提供されるコンポーネントはすべてTypeScriptで記述されています。
- Tailwind CSS: スタイリングの根幹。ユーティリティファーストなアプローチで、カスタマイズ性を高めています。
- Radix UI: アクセシビリティ、キーボード操作、状態管理など、コンポーネントの機能的な基盤を提供。
- Tailwind Variants (cva): Tailwind CSSでVariantシステムを効率的に定義・管理するためのライブラリ。
- Lucide Icons: シンプルで一貫性のあるアイコンセット。
導入準備:プロジェクトのセットアップ
shadcn/ui
を利用するには、まずReactまたはNext.jsプロジェクトと、Tailwind CSSのセットアップが必要です。Next.jsを使用する場合、新しいプロジェクトを作成すればTailwind CSSはデフォルトで含まれることが多いので、セットアップは比較的簡単です。
1. Node.jsのインストール
まだNode.jsがインストールされていない場合は、公式ウェブサイトから最新版をダウンロードしてインストールしてください。npmまたはyarn, pnpmといったパッケージマネージャーも同時にインストールされます。
2. Next.jsプロジェクトの作成
今回はNext.jsのApp Routerを前提に進めます。(Pages Routerでも利用可能ですが、推奨はApp Routerです)
bash
npx create-next-app@latest my-shadcn-app
プロジェクト作成時の設定は以下のように推奨されます。
What is your project name? my-shadcn-app
Would you like to use TypeScript? Yes
Would you like to use ESLint? Yes
Would you like to use Tailwind CSS? Yes
Would you like to use `src/` directory? No (or Yes, depends on your preference)
Would you like to use App Router? Yes (recommended)
Would you like to customize the default import alias (@/*)? Yes
What import alias would you like configured? @/*
これで、TypeScript、ESLint、Tailwind CSS、App Routerが有効化されたNext.jsプロジェクトが作成されます。
3. shadcn-ui CLIのインストール
shadcn/ui
のコンポーネントをプロジェクトに追加するには、専用のCLIツールを使用するのが最も効率的です。このCLIツールは、ローカルにインストールする必要はありません。npx
を使って直接実行できます。
初めてshadcn/ui
の設定を行う際に、CLIがプロジェクトに合わせた初期設定を対話形式で行ってくれます。
shadcn/uiの初期設定 (npx shadcn-ui init
)
プロジェクトの準備ができたら、ターミナルでプロジェクトのルートディレクトリに移動し、以下のコマンドを実行します。
bash
npx shadcn-ui init
このコマンドを実行すると、shadcn/ui
のCLIが対話形式でプロジェクトの初期設定を行います。いくつかの質問に答える必要があります。
一つずつ質問内容と選択肢、その意味を解説します。
-
Would you like to use TypeScript?
- Yes / No
- プロジェクトがTypeScriptを使用しているか尋ねています。Next.jsプロジェクトを上記手順で作成していれば「Yes」を選択します。ほとんどのモダンなReact/Next.jsプロジェクトではTypeScriptが推奨されます。
-
Which style would you like to use?
- Default / New York
shadcn/ui
が提供するスタイルのプリセットを選択します。「Default」はより標準的なデザイン、「New York」はよりモダンで洗練されたデザインです。どちらを選んでも後で簡単にカスタマイズできますが、プロジェクトの全体的なデザイントーンに近い方を選ぶと良いでしょう。- 選択すると、そのスタイルに基づいたTailwind CSSの設定(特にカラーパレット)が自動的に生成され、
tailwind.config.js
やCSS変数に反映されます。
-
Which color would you like to use as base color?
- (様々な色オプションが表示されます)
- プロジェクトのベースとなるカラーパレットを選択します。選択した色に基づき、Tailwind CSSの設定やCSS変数にアクセントカラーなどが定義されます。これも後から自由にカスタマイズ可能です。
-
Where is your tailwind.config.js located?
- デフォルト値:
tailwind.config.js
- Tailwind CSSの設定ファイルのパスを指定します。特に変更していなければデフォルトのパスで問題ありません。
- デフォルト値:
-
Global CSS file?
- デフォルト値:
app/globals.css
(App Routerの場合) またはstyles/globals.css
(Pages Routerの場合) - グローバルCSSファイルのパスを指定します。
shadcn/ui
のスタイル(特にCSS変数やベーススタイル)はこのファイルに追記されます。Next.jsのApp Routerテンプレートではapp/globals.css
が標準です。
- デフォルト値:
-
Configure the import alias for components?
- Yes / No
- コンポーネントをインポートする際のエイリアスを設定するか尋ねています。「Yes」を選択することを強く推奨します。これにより、
import { Button } from '@/components/ui/button';
のように、プロジェクトルートからの相対パスではなく、エイリアスを使った絶対パスでコンポーネントをインポートできるようになり、可読性が向上します。
-
What import alias would you like configured for components?
- デフォルト値:
@/components
- コンポーネントのエイリアス名を指定します。通常、デフォルトの
@/components
で問題ありません。
- デフォルト値:
-
Configure the import alias for utils?
- Yes / No
- ユーティリティ関数(例:
cn
関数)をインポートする際のエイリアスを設定するか尋ねています。「Yes」を選択することを強く推奨します。
-
What import alias would you like configured for utils?
- デフォルト値:
@/lib
- ユーティリティ関数のエイリアス名を指定します。通常、デフォルトの
@/lib
で問題ありません。
- デフォルト値:
-
Are you using React Server Components?
- Yes / No
- Next.js App Routerを使用しているか尋ねています。App Routerを使用している場合は「Yes」を選択します。これにより、Server ComponentsとClient Componentsの境界を考慮した設定(特に
'use client'
ディレクティブの位置など)が行われます。Pages Routerを使用している場合は「No」を選択します。
設定が完了すると、プロジェクトのルートディレクトリにcomponents.json
という設定ファイルが作成されます。このファイルには、上記の対話で入力した設定内容がJSON形式で保存されており、今後npx shadcn-ui add
コマンドを実行する際に参照されます。
また、選択したスタイルやベースカラーに応じたCSS変数がglobals.css
ファイルに追記され、ユーティリティ関数などがlib/utils.ts
に生成されます(エイリアス設定した場合)。
コンポーネントの追加と使い方
初期設定が完了したら、いよいよコンポーネントを追加してアプリケーションで使用できます。コンポーネントの追加は、npx shadcn-ui add
コマンドを使って行います。
例えば、Buttonコンポーネントを追加する場合、以下のコマンドを実行します。
bash
npx shadcn-ui add button
コマンドを実行すると、shadcn/ui
のコンポーネントリストからbutton
が選択され、依存するRadix UIのパッケージがインストールされた後、components.json
に設定されたパス(デフォルトではcomponents/ui
)の下にbutton.tsx
ファイルが生成されます。
生成されたcomponents/ui/button.tsx
ファイルを見てみましょう(内容は簡略化しています)。
“`typescript
import * as React from “react”
import { Slot } from “@radix-ui/react-slot”
import { cva, type VariantProps } from “class-variance-authority”
import { cn } from “@/lib/utils” // 設定したエイリアスでutils関数をインポート
// Tailwind Variants (cva) を使って、variantとsizeのスタイルを定義
const buttonVariants = cva(
“inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50”,
{
variants: {
variant: {
default: “bg-primary text-primary-foreground hover:bg-primary/90”,
destructive: “bg-destructive text-destructive-foreground hover:bg-destructive/90”,
outline: “border border-input bg-background hover:bg-accent hover:text-accent-foreground”,
secondary: “bg-secondary text-secondary-foreground hover:bg-secondary/80”,
ghost: “hover:bg-accent hover:text-accent-foreground”,
link: “text-primary underline-offset-4 hover:underline”,
},
size: {
default: “h-10 px-4 py-2”,
sm: “h-9 rounded-md px-3”,
lg: “h-11 rounded-md px-8”,
icon: “h-10 w-10”,
},
},
defaultVariants: {
variant: “default”,
size: “default”,
},
}
)
export interface ButtonProps
extends React.ButtonHTMLAttributes
VariantProps
asChild?: boolean // Radix UIのSlot機能を使用するためのプロパティ
}
const Button = React.forwardRef
({ className, variant, size, asChild = false, …props }, ref) => {
const Comp = asChild ? Slot : “button” // asChildがtrueならRadix UIのSlotを使う
return (
)
}
)
Button.displayName = “Button”
export { Button, buttonVariants }
“`
このコードから、いくつかの重要な点が見て取れます。
- Radix UIの利用:
Slot
コンポーネントがインポートされています。これはRadix UIが提供する、プロパティを子要素に引き渡すためのユーティリティです。asChild
プロパティを使うことで、Buttonコンポーネント自体はスタイルとロジックだけを提供し、DOM要素は外部から渡された要素(例えばNext.jsの<Link>
など)にレンダリングを委ねることができます。 cva
によるVariants定義:class-variance-authority
(cva
)ライブラリを使って、variant
(default
,destructive
など)とsize
(default
,sm
など)に応じたTailwind CSSクラスが定義されています。cn
ユーティリティ関数:lib/utils.ts
からインポートされたcn
関数は、clsx
(クラス名を条件付きで結合)とtailwind-merge
(Tailwind CSSクラスの競合を解決)を組み合わせたユーティリティです。これにより、cva
で生成されたクラスと、ユーザーがclassName
プロパティで指定したクラスを安全に結合できます。- Forwarding Ref:
React.forwardRef
を使用して、外部から渡されたref
をネイティブの<button>
要素に転送しています。これは、フォームライブラリなどと連携する際に重要です。
アプリケーションでの使用方法
追加したButtonコンポーネントは、通常のReactコンポーネントと同じようにインポートして使用できます。
“`typescript jsx
import { Button } from “@/components/ui/button”;
export default function HomePage() {
return (
Welcome to shadcn/ui App
{/* デフォルトボタン */}
<Button>Click Me</Button>
{/* Secondaryボタン */}
<Button variant="secondary" className="mt-4">Secondary Button</Button>
{/* Destructiveボタン (赤色) */}
<Button variant="destructive" size="lg" className="mt-4">Delete Item</Button>
{/* Linkとして使用 (asChildとNext.js Link) */}
<Button asChild variant="link" className="mt-4">
<a href="/about">About Us</a> {/* または Next.jsの <Link href="/about">About Us</Link> */}
</Button>
</div>
);
}
“`
このように、variant
やsize
プロパティ、そしてTailwind CSSクラスを直接指定できるclassName
プロパティを使って、簡単に見た目や挙動をカスタマイズできます。
主要なshadcn/uiコンポーネントとその特徴
shadcn/ui
には、Button以外にも多くの高機能なコンポーネントが用意されています。いくつか代表的なものを紹介します。
- Input, Label, Form:
- 基本的なフォーム要素。
react-hook-form
やバリデーションライブラリ(zod
など)との連携を想定して設計されています。Form
コンポーネントはフォームの状態管理やバリデーション結果の表示を助けます。
- 基本的なフォーム要素。
- Card:
- コンテンツをグループ化するためのコンテナコンポーネント。Header, Content, Footerといったサブコンポーネントに分かれており、柔軟なレイアウトが可能です。
- Dialog (Modal):
- オーバーレイ表示されるモーダルダイアログ。Radix UIのDialogプリミティブを使用しており、アクセシビリティ(フォーカストラップ、エスケープキーでの閉じるなど)が考慮されています。
- Dropdown Menu:
- ボタンクリックや右クリックなどで表示されるドロップダウンメニュー。MenuItem, Separatorなどの要素を持ちます。Radix UIのDropdown Menuプリミティブを使用。
- Table:
- 構造化されたデータを表示するためのテーブルコンポーネント。Header, Body, Cellなどの要素を持ち、基本的なテーブルレイアウトを提供します。データ表示ライブラリ(例: TanStack Table)と組み合わせて使用することが多いです。
- Data Table:
- TanStack Table(react-table v8)と連携して、ソート、フィルタリング、ページネーションなどの機能を持つ高機能なテーブルを実装するためのコンポーネントおよびフック。複雑なデータ表示に非常に強力です。
- Calendar:
- 日付を選択するためのカレンダーUI。
react-day-picker
ライブラリの上に構築されており、日付範囲選択や特定の日の無効化など、様々なオプションがあります。
- 日付を選択するためのカレンダーUI。
- Select:
- ドロップダウン形式の選択肢リスト。Radix UIのSelectプリミティブを使用しており、キーボード操作やアクセシビリティに優れています。
- Command:
- コマンドパレットやオートコンプリート、フィルタリング可能なリストなどに使用できるコンポーネント。
cmdk
ライブラリの上に構築されており、非常に高速な検索・フィルタリングが可能です。Comboboxとしても利用されます。
- コマンドパレットやオートコンプリート、フィルタリング可能なリストなどに使用できるコンポーネント。
- Tabs:
- コンテンツをタブ形式で切り替えるためのコンポーネント。Radix UIのTabsプリミティブを使用。
- Accordion:
- クリックでコンテンツの表示・非表示を切り替えるアコーディオンパネル。Radix UIのAccordionプリミティブを使用。
- Carousel:
- カルーセル(スライダー)コンポーネント。
embla-carousel-react
ライブラリの上に構築されており、タッチ操作やレスポンシブ対応が可能です。
- カルーセル(スライダー)コンポーネント。
- Tooltip, Popover:
- 要素にホバー/クリックした際に表示されるツールチップやポップオーバー。Radix UIのプリミティブを使用。
- Toast:
- 画面の隅に一時的に表示される通知メッセージ。
react-toastify
またはsonner
といったトーストライブラリと連携して使用します。
- 画面の隅に一時的に表示される通知メッセージ。
- Navigation Menu:
- 複雑なドロップダウンメニューやホバー可能なメガメニューなどを構築するためのコンポーネント。Radix UIのNavigation Menuプリミティブを使用。
これらのコンポーネントは、いずれもnpx shadcn-ui add <component-name>
で個別に追加でき、追加されたコードを自由にカスタマイズできるのが最大の強みです。それぞれのコンポーネントのコードを確認することで、Radix UIやTailwind CSS Variantsを使った高品質なコンポーネント設計パターンを学ぶこともできます。
カスタマイズの深掘り:デザインと構造を自由自在に操る
shadcn/ui
の最大の魅力は、その圧倒的なカスタマイズ性です。単にテーマカラーを変えるだけでなく、コンポーネントの構造や振る舞いにまで踏み込んで変更できます。カスタマイズは、主に以下の方法で行います。
1. スタイルのカスタマイズ
スタイルのカスタマイズは、Tailwind CSSとCSS変数を中心に行います。
-
tailwind.config.js
の編集:- プロジェクトのベースとなるカラーパレット、フォント、ブレークポイント、スペーシングなどを定義します。
shadcn/ui init
で生成された設定には、CSS変数を参照する形でカラーが定義されています。 -
例: テーマカラーの変更
“`javascript
// tailwind.config.js
const { fontFamily } = require(“tailwindcss/defaultTheme”)/ @type {import(‘tailwindcss’).Config} */
module.exports = {
darkMode: [“class”], // ダークモード設定
content: [
“./pages//.{ts,tsx}”,
“./components//.{ts,tsx}”,
“./app//*.{ts,tsx}”,
“./src//*.{ts,tsx}”,
],
theme: {
container: {
center: true,
padding: “2rem”,
screens: {
“2xl”: “1400px”,
},
},
extend: {
colors: {
// shadcn/ui init で生成された CSS変数を参照するカラー定義
border: “hsl(var(–border))”,
input: “hsl(var(–input))”,
ring: “hsl(var(–ring))”,
background: “hsl(var(–background))”,
foreground: “hsl(var(–foreground))”,
primary: {
DEFAULT: “hsl(var(–primary))”,
foreground: “hsl(var(–primary-foreground))”,
},
secondary: {
DEFAULT: “hsl(var(–secondary))”,
foreground: “hsl(var(–secondary-foreground))”,
},
destructive: {
DEFAULT: “hsl(var(–destructive))”,
foreground: “hsl(var(–destructive-foreground))”,
},
muted: {
DEFAULT: “hsl(var(–muted))”,
foreground: “hsl(var(–muted-foreground))”,
},
accent: {
DEFAULT: “hsl(var(–accent))”,
foreground: “hsl(var(–accent-foreground))”,
},
popover: {
DEFAULT: “hsl(var(–popover))”,
foreground: “hsl(var(–popover-foreground))”,
},
card: {
DEFAULT: “hsl(var(–card))”,
foreground: “hsl(var(–card-foreground))”,
},
},
borderRadius: {
// CSS変数 –radius を参照する border-radius 定義
lg:var(--radius)
,
md:calc(var(--radius) - 2px)
,
sm:calc(var(--radius) - 4px)
,
},
keyframes: {
“accordion-down”: {
from: { height: “0” },
to: { height: “var(–radix-accordion-content-height)” },
},
“accordion-up”: {
from: { height: “var(–radix-accordion-content-height)” },
to: { height: “0” },
},
},
animation: {
“accordion-down”: “accordion-down 0.2s ease-out”,
“accordion-up”: “accordion-up 0.2s ease-out”,
},
},
},
plugins: [require(“tailwindcss-animate”)], // アニメーション用プラグイン
}
``
primary
ここで定義されている,
secondaryなどの色は、
globals.cssで定義されたCSS変数
–primary,
–secondary`などを参照しています。
- プロジェクトのベースとなるカラーパレット、フォント、ブレークポイント、スペーシングなどを定義します。
-
globals.css
の編集(CSS変数):shadcn/ui init
で生成されたCSS変数(--background
,--foreground
,--primary
など)を直接編集することで、UI全体の配色テーマを変更できます。これらの変数は、tailwind.config.js
や各コンポーネント内のTailwindクラスから参照されています。-
例: ライトテーマとダークテーマのCSS変数定義
“`css
/ globals.css /
@tailwind base;
@tailwind components;
@tailwind utilities;@layer base {
:root {
–background: 0 0% 100%; / HSL for background /
–foreground: 222.2 84% 4.9%; / HSL for foreground /--card: 0 0% 100%; --card-foreground: 222.2 84% 4.9%; --popover: 0 0% 100%; --popover-foreground: 222.2 84% 4.9%; --primary: 222.2 47.4% 11.2%; /* 主なアクションの色 */ --primary-foreground: 210 40% 98%; /* 主なアクションの文字色 */ /* 他のカラー変数定義 */ --border: 214.3 31.4% 91.4%; --input: 214.3 31.4% 91.4%; --ring: 222.2 84% 4.9%; --radius: 0.5rem; /* border-radiusの基準値 */
}
.dark {
–background: 222.2 84% 4.9%;
–foreground: 210 40% 98%;--card: 222.2 84% 4.9%; --card-foreground: 210 40% 98%; --popover: 222.2 84% 4.9%; --popover-foreground: 210 40% 98%; --primary: 210 40% 98%; --primary-foreground: 222.2 47.4% 11.2%; /* 他のダークテーマ用カラー変数定義 */ --border: 217.2 32.6% 17.5%; --input: 217.2 32.6% 17.5%; --ring: 212.7 26.8% 83.9%;
}
}@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
``
.darkセレクタ内で別のCSS変数を定義することで、簡単にダークモードを実装できます。
next-themesのようなライブラリと組み合わせるのが一般的です。
–radius`変数を変更することで、ボタンやカードなどの角丸の度合いを一括で変更できます。
-
コンポーネントファイルの直接編集:
- プロジェクトに追加された各コンポーネントファイル(例:
components/ui/button.tsx
)を直接編集し、適用されているTailwind CSSクラスやcva
定義を変更します。これは、特定のコンポーネントのスタイルだけを大きく変えたい場合に有効です。ただし、npx shadcn-ui add
でコンポーネントをアップデートすると変更が上書きされる可能性があるため、編集内容を控えておくか、慎重に行う必要があります。
- プロジェクトに追加された各コンポーネントファイル(例:
className
プロパティによる上書き:- コンポーネントを使用する側で、
className
プロパティを使って追加のTailwind CSSクラスを指定します。cn
ユーティリティ関数のおかげで、元のスタイルを壊すことなく新しいスタイルを追加または上書きできます。 - 例: ボタンのパディングやマージンを変更
jsx
<Button className="px-8 py-4 mt-6">More Padding</Button>
- コンポーネントを使用する側で、
cva
のカスタムバリアント追加:- コンポーネントファイル内で、
cva
定義に新しいvariant
やsize
を追加できます。 - 例: ボタンに新しいカラーバリアントを追加
typescript
// components/ui/button.tsx (編集)
const buttonVariants = cva(
// ...既存のクラス
{
variants: {
variant: {
// ...既存のバリアント
success: "bg-green-500 text-white hover:bg-green-600", // 新しいバリアントを追加
},
// ...既存のsize
},
// ...defaultVariants
}
);
これで<Button variant="success">Success</Button>
のように使用できるようになります。
- コンポーネントファイル内で、
2. ロジック/構造のカスタマイズ
コンポーネントのスタイリングだけでなく、HTML構造やJavaScriptのロジックにも踏み込んでカスタマイズできます。
- コンポーネントファイルの直接編集:
components/ui/dialog.tsx
のようなファイルを直接編集して、Radix UIのプリミティブの使い方を変更したり、独自の要素を追加したりできます。- 例えば、Dialogのクローズボタンの位置を変えたり、モーダルが開いたときに特定の処理を追加したりといったことが可能です。
- Radix UIプロパティの活用:
shadcn/ui
コンポーネントは内部でRadix UIのプリミティブを使用しています。Radix UIのドキュメントを参照し、そのプリミティブが提供するプロパティ(例:DialogTrigger
のonOpenChange
)を活用することで、コンポーネントの挙動をカスタマイズできます。shadcn/ui
のラッパーコンポーネントは、Radix UIのプロパティをそのまま受け付けられるように設計されていることが多いです。
asChild
とコンポジション:- 多くの
shadcn/ui
コンポーネントはasChild
プロパティをサポートしています。これをtrue
に設定すると、コンポーネント自身はDOM要素をレンダリングせず、その子要素にスタイルやイベントリスナーといったプロパティを引き渡します。これにより、Next.jsの<Link>
や独自のカスタム要素など、任意の要素をshadcn/ui
のスタイルでレンダリングできます。これはReactのコンポジションの考え方に基づいており、非常に強力なカスタマイズ手法です。 -
例: Next.jsのLinkをButtonのようにスタイリング
“`jsx
import Link from “next/link”;
import { Button } from “@/components/ui/button”;function NavLink({ href, children }) {
return (
// asChild={true} で Buttonのスタイルと挙動をLinkに引き渡す
);
}// 使用例
Go to Dashboard
“`
- 多くの
開発ワークフローの効率化
shadcn/ui
はUI実装のスピードアップに貢献しますが、さらにワークフローを効率化するためのヒントがいくつかあります。
- コンポーネントの構造理解:
- 追加したコンポーネントのコード(特にRadix UIや
cva
の使い方)を積極的に読むことで、shadcn/ui
の設計思想やカスタマイズ方法への理解が深まります。これは、将来的に独自のコンポーネントを作成したり、既存のコンポーネントを大きく変更したりする際に非常に役立ちます。
- 追加したコンポーネントのコード(特にRadix UIや
- StorybookやChromaticとの連携:
- UIコンポーネントのカタログ化や視覚的回帰テストのために、Storybookを導入するのは非常に有効です。
shadcn/ui
コンポーネントもStorybookでドキュメント化・テストできます。Chromaticのようなサービスと連携すれば、UIの変更が意図しない影響を与えていないかを自動でチェックできます。
- UIコンポーネントのカタログ化や視覚的回帰テストのために、Storybookを導入するのは非常に有効です。
- VS Code拡張機能:
- Tailwind CSS IntelliSense拡張機能は、Tailwindクラスの補完やホバーでのスタイルプレビューを提供し、スタイリング作業を大幅に効率化します。また、ESLintやPrettierを設定することで、コードの品質と一貫性を保つことができます。
- Formライブラリとの連携:
- 複雑なフォームを扱う場合、
react-hook-form
とzod
のようなバリデーションライブラリとの組み合わせが非常に強力です。shadcn/ui
のForm
コンポーネントはこれらのライブラリとの連携を想定して設計されており、ボイラープレートコードを削減し、宣言的にフォームを構築できます。Form
コンポーネントのドキュメントやexampleコードを参照すると良いでしょう。
- 複雑なフォームを扱う場合、
- カスタムコンポーネントの作成:
shadcn/ui
のスタイルやパターン(CSS変数、cva
、cn
ユーティリティ、Radix UIの利用)を参考にして、プロジェクト固有のカスタムコンポーネントを作成し、components/ui
ディレクトリに追加していくことで、一貫性のあるデザインシステムを構築できます。
高度なトピック
- App RouterとServer Componentsでの利用:
- Next.jsのApp Routerでは、Server ComponentsとClient Componentsが混在します。
shadcn/ui
のコンポーネントは基本的にClient Componentsとして設計されています(状態やインタラクションを持つため)。コンポーネントファイルの上部に'use client'
ディレクティブが付与されていることを確認してください。Server Component内でshadcn/ui
コンポーネントを使用する場合は、それがクライアントコンポーネントとしてインポート・レンダリングされるように注意が必要です。
- Next.jsのApp Routerでは、Server ComponentsとClient Componentsが混在します。
- アニメーションの追加:
shadcn/ui
はデフォルトでRadix UIによって提供される基本的なアニメーションを含んでいます。よりリッチなアニメーションが必要な場合は、Framer Motionなどのライブラリと組み合わせるのが一般的です。asChild
プロパティを使用して、shadcn/ui
コンポーネントの子要素としてFramer Motionコンポーネントを配置するパターンがよく使われます。
- パフォーマンスに関する考慮事項:
shadcn/ui
は必要なコンポーネントのみを追加するため、従来のライブラリよりもバンドルサイズは小さくなります。しかし、多くのコンポーネントを含むページでは、それらのコンポーネントがすべてクライアント側でハイドレーションされるため、JavaScriptの実行コストが発生します。必要に応じて、動的なインポート(React.lazy
+Suspense
またはnext/dynamic
)を利用して、UIコンポーネントのロードを遅延させることを検討してください。
- テスト戦略:
shadcn/ui
コンポーネントは、React Testing Libraryなどを用いて通常のReactコンポーネントと同様にテストできます。Radix UIをベースにしているため、アクセシビリティ属性(role
,aria-*
)が適切に設定されており、ユーザーの操作に近い形でコンポーネントをテストしやすいという利点があります。特にインタラクションが多いコンポーネント(Dialog, Dropdown Menuなど)は、これらの属性をセレクタとして利用するとテストの信頼性が高まります。
利点と欠点・注意点
shadcn/ui
は多くの利点がありますが、いくつかの欠点や注意点も存在します。導入を検討する際には、これらを理解しておくことが重要です。
利点
- 高いカスタマイズ性: プロジェクトにコードがコピーされるため、デザイン、構造、ロジックを完全に制御できます。
- 優れたパフォーマンス: 不要なコードを含まず、依存関係が最小限に抑えられます。
- Tailwind CSSとの強力な統合: Tailwind CSSをベースにしているため、既存のTailwindプロジェクトにシームレスに組み込めます。
- Radix UIによるアクセシビリティと品質: 機能的な基盤がしっかりしており、アクセシビリティの懸念が軽減されます。
- コードの学習機会: 高品質なコンポーネントの実装コードを直接見られるため、UI開発のベストプラクティスを学べます。
- 依存関係の管理がシンプル: ライブラリ全体のアップデートではなく、必要なコンポーネントごとに管理できます。
欠点・注意点
- 初期設定の手間:
npx shadcn-ui init
による設定や、コンポーネントごとの追加コマンドが必要です。 - コンポーネントのアップデートが手動: 新しいバージョンがリリースされた場合、
npx shadcn-ui add <component-name>@latest
のようにコマンドを再実行してコンポーネントファイルを上書きする必要があります。ローカルでの変更は失われるため、手動でマージするか、変更内容を管理する必要があります。 - Tailwind CSSの知識が必須: スタイリングはTailwind CSSに依存しているため、Tailwind CSSを使ったことがない場合は学習が必要です。
- デザインシステムの構築責任: 既成のデザインシステムが提供されるわけではなく、CSS変数やTailwind設定を通じて、ある程度自分でデザインシステムを構築・維持していく必要があります。
- 依存関係の分散: 各コンポーネントが必要とするRadix UIなどの依存ライブラリは個別に
package.json
に追加されます。従来のモノリシックなUIライブラリと比べて、依存関係リストが長くなることがあります。 - 「ライブラリ」ではないことの理解:
npm install shadcn-ui
のように一括で導入・管理するイメージで捉えると混乱します。あくまで「コードをコピペするツールとコード集」という認識が重要です。
これらの点を踏まえると、shadcn/ui
は以下のようなプロジェクトや開発者に向いています。
- Tailwind CSSを使った開発に慣れている、または使いたいプロジェクト。
- デザインのカスタマイズ性が非常に重要視されるプロジェクト。
- バンドルサイズやパフォーマンスを最適化したいプロジェクト。
- 特定のデザインシステムやブランディングに厳密に従う必要があるプロジェクト。
- コンポーネントの実装を自身でコントロールしたい開発チーム。
逆に、Tailwind CSSを使いたくない、迅速にプロトタイプを作成したい(デザインの細かい調整は後回し)、あるいは既成の強固なデザインシステム(Material DesignやAnt Designなど)に完全に準拠したい、といったケースでは、従来のUIライブラリの方が適している可能性もあります。
まとめ:shadcn/uiが切り開くUI開発の未来
この記事では、React/Next.js開発における新たなUI実装の潮流として、shadcn/ui
を詳細に解説しました。
shadcn/ui
は、従来のUIコンポーネントライブラリの課題(カスタマイズ性の限界、バンドルサイズ、抽象化)に対する強力なアンチテーゼとして登場しました。「ライブラリではなく、UIコンポーネントのコレクションをコピペでプロジェクトに追加する」というユニークなアプローチは、開発者にデザインと実装の主導権を取り戻させ、究極の柔軟性を提供します。
Tailwind CSSをスタイリングの基盤とし、Radix UIをアクセシビリティと機能の基盤とすることで、shadcn/ui
は美しい見た目、高い品質、そして優れたカスタマイズ性を両立しています。主要なコンポーネントは、モダンなウェブアプリケーションで必要とされるほとんどのUI要素をカバーしており、それらをnpx shadcn-ui add
コマンド一つで手軽に追加できます。
初期設定やコンポーネント追加の手間、アップデートの手動性といったトレードオフはありますが、それを補って余りあるカスタマイズ性とパフォーマンスのメリットは、特にTailwind CSSを愛用する開発者や、独自のデザインシステムを構築したいチームにとって魅力的でしょう。
shadcn/ui
は単なるUIコンポーネント集に留まらず、Tailwind CSS、Radix UI、Reactのコンポジションといったモダンなフロントエンド開発のベストプラクティスを凝縮した学習リソースでもあります。生成されるコードを読むことは、高品質なコンポーネント設計スキルを向上させる上で非常に価値があります。
この記事を読まれたあなたが、ぜひ実際に手を動かしてshadcn/ui
を試してみてください。きっと、その開発体験の快適さと、手軽に美しいUIを実装できるパワーに驚くはずです。React/Next.js開発におけるUI実装の「爆速化」と「美しさ」を両立させる旅は、shadcn/ui
とともに、ここから始まります。
今後のあなたのプロジェクトに、shadcn/ui
が役立てば幸いです。