言語を切り替える
テーマを切り替える

shadcn/ui インストールとテーマカスタマイズ完全ガイド(CSS変数付き)

正直なところ、shadcn/uiを初めて使った時、「npmパッケージじゃない」という仕組みに戸惑いました。コードをプロジェクトにコピーする?原始的すぎると思いました。

でも何度か使ってみると、これこそが強みだと気づきました。全コンポーネントのソースコードを所有でき、自由に変更でき、バージョン競合もなく、コンポーネントライブラリの設計に縛られることもありません。

今回はshadcn/uiのインストール設定とテーマカスタマイズについて、特にCSS変数を使ってブランドデザインシステムを作る方法を紹介します。この記事を読み終われば、5分で基本設定ができ、1時間ほどでテーマを好みの色に調整できるようになります。


1. クイックインストール:2つの方法

方法1:CLIで一発初期化(推奨)

新規プロジェクトならこのコマンドを実行:

npx shadcn@latest init

実行すると質問が表示されます:TypeScriptかJavaScriptか?どのスタイルか?デフォルトテーマは?すべて対話式なので、指示に従って選択します。

インストール完了後、プロジェクトに以下のファイルが追加されます:

  • components.json - 設定ファイル
  • lib/utils.ts - ユーティリティ関数
  • components/ui/ - コンポーネント格納ディレクトリ

コンポーネント追加も簡単、ボタンなら:

npx shadcn@latest add button

コンポーネントコードが自動的に components/ui/button.tsx にコピーされ、importして使うだけです。

ここに落とし穴があります:プロジェクトがすでに開発中の場合、tailwind.config.jsとglobals.cssに多くの設定があるかもしれません。shadcnのinitコマンドはこれらのファイルを上書きするので、プロジェクト開始時にインストールするのがベストです。

あるブロガーが言っていました:shadcn/uiをプロジェクトの「最初の依存関係」として扱い、後で追加しないように。痛い目を見ました。

方法2:手動インストール(既存プロジェクト向け)

プロジェクトがすでに完成に近く、CLIによる設定上書きのリスクが高い場合、手動でインストールします。

ステップは以下の通り:

ステップ1:Tailwind CSSがインストールされているか確認

shadcnのコンポーネントはTailwindでスタイリングされているので、まだなら先にTailwindをインストールします。公式ドキュメントが分かりやすいです。

ステップ2:依存関係をインストール

npm install class-variance-authority clsx tailwind-merge
npm install lucide-react

class-variance-authority(略称CVA)は便利です。後でコンポーネントバリアントを作る時に使います。

ステップ3:パスエイリアスを設定

tsconfig.json に追加:

{
  "compilerOptions": {
    "paths": {
      "@/*": ["./*"]
    }
  }
}

これで @/components/ui/button という形式でコンポーネントをimportでき、../../../ を書く必要がなくなります。

ステップ4:components.jsonを作成

プロジェクトルートにこのファイルを作成:

{
  "style": "new-york",
  "rsc": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "neutral",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils"
  }
}

cssVariables: true の行が重要です。Tailwindのユーティリティクラスではなく、CSS変数でテーマを作ることを意味します。

ステップ5:スタイルを追加

globals.css にshadcnのベーススタイルを追加します。テーマの説明で詳しく触れます。


2. テーマシステムを理解する:CSS変数の仕組み

shadcn/uiのテーマシステムはシンプルな規則に基づいています:すべての色に backgroundforeground の2つの変数があります。

どういうこと?例を見てみましょう:

:root {
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
}

--primary はボタンの背景色、--primary-foreground はボタン上の文字色です。このペアリングの利点は、1つの変数を変更するだけで、関連するすべてのコンポーネントが更新されることです。

CSS変数リスト

shadcn/uiはデフォルトで以下の変数を定義しています:

変数用途
--backgroundページ背景
--foregroundページ文字
--cardカード背景
--card-foregroundカード文字
--popoverポップアップ背景
--popover-foregroundポップアップ文字
--primaryメインカラー(ボタン、リンク)
--primary-foregroundメインカラー上の文字
--secondaryセカンダリカラー
--secondary-foregroundセカンダリカラー上の文字
--muted控えめな背景
--muted-foreground控えめな文字
--accentアクセントカラー
--accent-foregroundアクセントカラー上の文字
--destructive危険操作(削除ボタン)
--destructive-foreground危険操作上の文字
--borderボーダー
--input入力フィールド
--ringフォーカスリング

多いように見えますが、background/foreground のパターンを理解すれば、簡単に覚えられます。

HSLフォーマットの秘密

shadcnの色値が標準的なHSLフォーマットではないことに気づくかもしれません:

/* ❌ 標準HSL */
--primary: hsl(222.2, 47.4%, 11.2%);

/* ✅ shadcnフォーマット */
--primary: 222.2 47.4% 11.2%;

なぜこの「裸」のフォーマットで書くのか?

Tailwindは透明度修飾子をサポートしているからです。例えば bg-primary/50 は50%透明度のプライマリカラーを意味します。変数が完全な hsl() フォーマットの場合、この機能は使えません。

裸フォーマットで書くと、Tailwindが自動的に hsl() と透明度を追加してくれます。賢い設計です。


3. ブランドテーマをカスタマイズ

方法1:CSS変数を直接変更

最もシンプルな方法は、globals.css を開き、:root セクションを見つけ、色値を変更することです。

例えば、プライマリカラーをデフォルトの青から紫に変更:

:root {
  --primary: 270 60% 60%;
  --primary-foreground: 0 0% 100%;
}

.dark {
  --primary: 270 60% 70%;
  --primary-foreground: 0 0% 0%;
}

保存後、bg-primary を使っているすべてのコンポーネントが紫になります。

方法2:OKLCHカラースペースを使用(Tailwind v4)

Tailwind v4を使用している場合、OKLCHカラースペースを検討できます。HSLと比較して、OKLCHは色の知覚が人間の視覚に近く、より均一なカラースケールが生成されます。

:root {
  --primary: oklch(0.6 0.2 270);
  --primary-foreground: oklch(0.98 0 0);
}

oklch(0.6 0.2 270) の3つのパラメータは:

  • 0.6 - 明度(0-1)
  • 0.2 - 彩度(0-0.4程度)
  • 270 - 色相角度(0-360)

方法3:オンラインツールを使用

色を設定するのが面倒?オンラインツールを使いましょう。

おすすめ:Shadcn Theme Generator

メインカラーを選択すると、ツールがライトとダークの両方の完全なCSS変数セットを自動生成します。globals.css にコピペするだけです。


4. ダークモード設定

next-themesでテーマ切り替えを実装

shadcn/ui自体にはテーマ切り替え機能が含まれていませんが、next-themesライブラリで実現できます。

まずインストール:

npm install next-themes

次に layout.tsx で設定:

import { ThemeProvider } from "next-themes"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="ja" suppressHydrationWarning>
      <body>
        <ThemeProvider
          attribute="class"
          defaultTheme="system"
          enableSystem
        >
          {children}
        </ThemeProvider>
      </body>
    </html>
  )
}

重要なポイント:

  • suppressHydrationWarning は必須。なければハイドレーション警告が出ます
  • attribute="class" はクラス名でテーマを切り替えることを意味します
  • defaultTheme="system" はデフォルトでシステム設定に従うことを意味します
  • enableSystem はシステムテーマ検出を有効にします

テーマ切り替えボタンを作成

useTheme フックで現在のテーマと切り替え関数を取得:

import { useTheme } from "next-themes"
import { Moon, Sun } from "lucide-react"

export function ThemeToggle() {
  const { theme, setTheme } = useTheme()

  return (
    <button
      onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
      className="p-2 rounded-md hover:bg-accent"
    >
      {theme === "dark" ? <Sun size={20} /> : <Moon size={20} />}
    </button>
  )
}

デフォルトでダークモード

サイトをデフォルトでダークモードにしたい場合、2つの方法があります:

方法1:darkクラスをハードコード

<html lang="ja" className="dark">

これでテーマがダークに固定され、切り替えできなくなります。

方法2:デフォルトテーマを設定

<ThemeProvider
  attribute="class"
  defaultTheme="dark"  // デフォルトダーク
  enableSystem={false} // システム検出を無効化
>

ユーザーは手動で切り替えられますが、初期状態はダークになります。


5. 高度なカスタマイズ:コンポーネントバリアント

CVAでカスタムバリアントを作成

ボタンに「危険」「成功」「グラデーション」など複数のスタイルを追加したい場合があります。CVAを使うと、これらのバリアントを簡単に定義できます。

import { cva, type VariantProps } from "class-variance-authority"

const buttonVariants = cva(
  "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
  {
    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<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {}

コンポーネントで使用:

<button className={buttonVariants({ variant: "destructive", size: "lg" })}>
  削除
</button>

shadcnコンポーネントのソースコードを直接変更しない

これはベストプラクティスの問題です。

shadcnのコンポーネントコードは自分のプロジェクトにありますが、オリジナルファイルを直接変更せず、ラッパーコンポーネントを作成することをお勧めします。

なぜ?shadcnは頻繁にコンポーネントを更新します。オリジナルファイルを変更すると、更新時に手動でマージする必要があり、面倒です。

より良い方法:

// components/brand-button.tsx
import { Button } from "@/components/ui/button"
import { cva } from "class-variance-authority"

const brandButtonVariants = cva("...", {
  variants: {
    brand: {
      primary: "bg-brand-primary text-white",
      secondary: "bg-brand-secondary text-black",
    },
  },
})

export function BrandButton({ brand, ...props }) {
  return <Button className={brandButtonVariants({ brand })} {...props} />
}

これでオリジナルのButtonコンポーネントは変更されず、独自のBrandButtonを作成でき、将来のshadcn更新もカスタマイズに影響しません。


6. よくある問題と注意点

問題1:インストール後にスタイルが効かない

以下を確認してください:

  1. globals.csslayout.tsx でimportされているか?
  2. Tailwindの content 設定に components/**/* が含まれているか?
  3. components.json のパス設定が正しいか?

問題2:テーマ切り替え時にちらつく

これは通常、ハイドレーションの不一致が原因です。以下を確認:

  1. <html> タグに suppressHydrationWarning があるか?
  2. ThemeProviderがアプリ全体をラップしているか?
  3. サーバーサイドレンダリング時にthemeを読み取っていないか(undefinedになります)

問題3:CSS変数が効かない

考えられる原因:

  1. 変数名のタイプミス(--primaryForeground ではなく --primary-foreground
  2. 対応する .dark スタイルがない
  3. 変数値のフォーマットが間違っている(裸HSLまたはOKLCHを使用)

問題4:コンポーネントスタイルの競合

プロジェクトにすでにスタイルシステムがある場合、shadcnと競合する可能性があります。解決策:

  1. shadcnコンポーネントにnamespaceを追加(例:shadcn-button
  2. Tailwindのlayer優先度を調整
  3. CVAで独自のバリアントを作成し、デフォルトスタイルに依存しない

7. まとめ

shadcn/uiのインストール設定は実はシンプルです。重要なのは「依存パッケージではなくコードをコピーする」という設計理念を理解することです。利点は完全なコントロール、欠点は各プロジェクトでコンポーネントコードを自分でメンテナンスする必要があることです。

テーマカスタマイズに関しては、CSS変数システムはエレガントに設計されています。いくつかの変数値を変更するだけで、アプリ全体の色が更新されます。next-themesと組み合わせれば、ライト/ダークモード切り替えも数行のコードで実現できます。

最後のアドバイス:

  1. 新規プロジェクトではCLI初期化を優先—手動設定の手間を省ける
  2. セマンティックな色変数を使用—具体的な色名ではなく、primary、secondaryなどを使用
  3. ライトとダークモード両方でコントラストをテスト—読みやすさを確保
  4. ソースを変更せずラッパーコンポーネントを作成—更新を容易に

次にテーマ付きUIを素早く構築する必要がある時、shadcn/uiを試してみてください。コピペの喜び、使ってみれば分かります。


shadcn/uiインストールとテーマカスタマイズ

shadcn/uiをゼロからインストールし、テーマシステムを設定し、ブランドデザインを構築

⏱️ 目安時間: 30 分

  1. 1

    ステップ1: CLIでクイック初期化

    新規プロジェクトでインストールコマンドを実行:

    • npx shadcn@latest init
    • TypeScript/New Yorkスタイル/デフォルトテーマを選択
    • CLIが設定を完了するのを待つ
  2. 2

    ステップ2: ブランドメインカラーを変更

    globals.cssのCSS変数を編集:

    • app/globals.cssを開く
    • :root配下の--primary変数を見つける
    • ブランドカラーに変更(HSLまたはOKLCHフォーマット)
    • コントラストのため--primary-foregroundも変更
  3. 3

    ステップ3: ダークモードを設定

    next-themesをインストールして設定:

    • npm install next-themes
    • layout.tsxにThemeProviderを追加
    • ハイドレーション警告を避けるためsuppressHydrationWarningを設定
    • テーマ切り替えコンポーネントを作成
  4. 4

    ステップ4: コンポーネントバリアントを作成

    CVAを使用してカスタムスタイルを定義:

    • class-variance-authorityをインストール
    • variantsとdefaultVariantsを定義
    • コンポーネントでbuttonVariants()を適用
    • オリジナルshadcnコンポーネントは変更しない

FAQ

shadcn/uiと従来のUIコンポーネントライブラリの違いは?
shadcn/uiはnpmパッケージではなく、コンポーネントのソースコードをプロジェクトにコピーします。利点は完全なコントロールとカスタマイズが可能でバージョン競合がないこと、欠点は各プロジェクトでコンポーネントコードを自分でメンテナンスする必要があることです。
なぜ新規プロジェクト初期化時にshadcn/uiをインストールすべき?
shadcnのinitコマンドはtailwind.config.jsとglobals.cssを上書きするからです。プロジェクトがすでに開発中の場合、これらのファイルの設定が上書きされるので、早めにインストールするのがベストです。
CSS変数を標準HSLではなく裸フォーマットで書く理由は?
裸フォーマット(例:222.2 47.4% 11.2%)はTailwindの透明度修飾子をサポートしているからです。例えばbg-primary/50で50%透明度を指定できます。完全なhsl()フォーマットではこの機能が使えません。
ブランドメインカラーを変更するには?
globals.cssを開き、:root配下の--primaryと--primary-foreground変数をブランドカラー値に変更します。保存後、bg-primaryを使用しているすべてのコンポーネントが自動的に更新されます。
ダークモードでちらつきが発生する理由は?
通常、ハイドレーションの不一致が原因です。htmlタグにsuppressHydrationWarning属性があるか、ThemeProviderがアプリ全体を正しくラップしているか、サーバーサイドレンダリング時にthemeを読み取っていないかを確認してください。
shadcnコンポーネントのソースコードを直接変更すべき?
お勧めしません。shadcnは頻繁にコンポーネントを更新します。オリジナルファイルを変更すると、更新時に手動でマージする必要があります。ラッパーコンポーネントを作成し、オリジナルは変更しない方が良いです。

参考資料

4 min read · 公開日: 2026年3月26日 · 更新日: 2026年3月26日

コメント

GitHubアカウントでログインしてコメントできます

関連記事