tailwind-theme-builder について
CSS 変数とダークモードを使い、Tailwind v4 と shadcn/ui のテーマを設定するスキルです。設定用ファイルや ThemeProvider、よくある設定不具合の対処法を提供します。
主な機能
- 01Vite プラグインによる Tailwind v4 の設定
- 02@theme inline による CSS 変数のマッピング
- 03ThemeProvider を使ったダークモード設定
- 04セマンティックなカラートークンの適用
- 05テーマ設定で起きやすい問題の診断
活用シーン
- 01テーマ対応の shadcn/ui プロジェクトを初期化
- 02ライト、ダーク、システムの各モードを追加
- 03ユーティリティクラスの欠落や色切り替え不具合を修正
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jezweb/ claude-skills --skill tailwind-theme-builderインストール後、Claude Code で/tailwind-theme-builderを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
assets/components.jsonindex.csstheme-provider.tsxtsconfig.app.jsonutils.tsvite.config.tsreferences/migration-guide.md詳細
Tailwind テーマビルダー
ダークモードを備えた、完全にテーマ設定された Tailwind v4 + shadcn/ui プロジェクトをセットアップします。設定済みの CSS、テーマプロバイダー、動作するコンポーネントライブラリを生成します。
アーキテクチャ:4 ステップのパターン
Tailwind v4 では、CSS 変数ベースのテーマ設定に特定のアーキテクチャが必要です。このパターンは必須です。手順を省略または変更すると、テーマが正しく機能しません。
仕組み
CSS Variable Definition --> @theme inline Mapping --> Tailwind Utility Class
--background --> --color-background --> bg-background
(with hsl() wrapper) (references variable) (generated class)
ダークモードの切り替え:
ThemeProvider toggles .dark class on <html>
--> CSS variables update automatically (.dark overrides :root)
--> Tailwind utilities reference updated variables
--> UI updates without re-render
ベストプラクティス
- セマンティックな名前:
--blue-500ではなく--primaryを使用します - 前景色との組み合わせ: すべての背景色に前景色が必要です(
--primary+--primary-foreground) - WCAG コントラスト: 通常のテキストは 4.5:1、大きなテキストは 3:1、UI コンポーネントは 3:1
- チャートの色:
@theme inlineマッピングを使って個別の変数を使用し、スタイルプロパティではvar(--chart-1)を参照します
ワークフロー
ステップ 1:依存関係をインストールする
pnpm add tailwindcss @tailwindcss/vite
pnpm add -D @types/node tw-animate-css
pnpm dlx shadcn@latest init
# Delete v3 config if it exists
rm -f tailwind.config.ts
ステップ 2:Vite を設定する
assets/vite.config.ts をコピーするか、Tailwind プラグインを追加します。
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
import path from 'path'
export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: { alias: { '@': path.resolve(__dirname, './src') } }
})
ステップ 3:4 ステップの CSS アーキテクチャ(必須)
この正確な順序が必要です。手順を省略すると、テーマが正しく機能しません。
src/index.css:
@import "tailwindcss";
@import "tw-animate-css";
/* 1. Define CSS variables at root (NOT inside @layer base) */
:root {
--background: hsl(0 0% 100%);
--foreground: hsl(222.2 84% 4.9%);
--primary: hsl(221.2 83.2% 53.3%);
--primary-foreground: hsl(210 40% 98%);
/* ... all semantic tokens */
}
.dark {
--background: hsl(222.2 84% 4.9%);
--foreground: hsl(210 40% 98%);
--primary: hsl(217.2 91.2% 59.8%);
--primary-foreground: hsl(222.2 47.4% 11.2%);
}
/* 2. Map variables to Tailwind utilities */
@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
}
/* 3. Apply base styles (NO hsl() wrapper here) */
@layer base {
body {
background-color: var(--background);
color: var(--foreground);
}
}
結果: bg-background、text-primary などが自動的に機能します。ダークモードは .dark クラスで切り替わります。セマンティックカラーには dark: バリアントは不要です。
ステップ 4:ダークモードをセットアップする
assets/theme-provider.tsx をコンポーネントディレクトリにコピーし、アプリをラップします。
import { ThemeProvider } from '@/components/theme-provider'
ReactDOM.createRoot(document.getElementById('root')!).render(
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<App />
</ThemeProvider>
)
テーマ切り替えを追加するには、ドロップダウンメニューをインストールしてから、以下の ModeToggle コンポーネントを使用します。
pnpm dlx shadcn@latest add dropdown-menu
// src/components/mode-toggle.tsx
import { Moon, Sun } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { useTheme } from "@/components/theme-provider"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>Light</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>Dark</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>System</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
ステップ 5:components.json を設定する
{
"tailwind": {
"config": "",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true
}
}
"config": "" は重要です。v4 は tailwind.config.ts を使用しません。
重要なルール
必ず行うこと:
:root/.dark内の色をhsl()で囲みます- すべての CSS 変数のマッピングに
@theme inlineを使用します @tailwindcss/viteプラグインを使用します(PostCSS は使用しません)tailwind.config.tsが存在する場合は削除します
行わないこと:
:root/.darkを@layer base内に配置する.dark { @theme { } }を使用する(v4 はネストされた @theme をサポートしていません)- 二重に囲む:
hsl(var(--background)) @layer baseクラスに@applyを使用する(代わりに@utilityを使用します)
18 の注意点すべて
すばやく原因を特定
| # | 症状 | 原因 | 解決策 |
|---|---|---|---|
| 1 | 変数が無視される/テーマが壊れる | @layer base 内の :root | :root と .dark をルートレベルに移動する |
| 2 | ダークモードの色が切り替わらない | .dark { @theme { } } | CSS 変数と単一の @theme inline を使用する |
| 3 | すべての色が黒または白になる | hsl() の二重ラップ | hsl(var(...)) ではなく var(--background) を使用する |
| 4 | bg-primary が生成されない | tailwind.config.ts に色を設定している | 設定ファイルを削除し、@theme inline を使用する |
| 5 | bg-background クラスがない | @theme inline ブロックがない | 変数をマッピングする @theme inline を追加する |
| 6 | shadcn コンポーネントが壊れる | components.json に設定パスがある | "config": ""(空文字列)を設定する |
| 7 | Tailwind が処理されない | PostCSS プラグインを使用している | @tailwindcss/vite プラグインに切り替える |
| 8 | @/ インポートが失敗する | パスエイリアスがない | tsconfig.app.json に paths を追加する |
| 9 | dark: バリアントが冗長 | dark:bg-primary-dark を使用している | bg-primary だけを使用する。変数で処理されます |
| 10 | あちこちで色がハードコードされている | bg-blue-600 dark:bg-blue-400 を使用している | bg-primary などのセマンティックトークンを使用する |
| 11 | クラスのマージで不具合が起きる | クラスを文字列連結している | @/lib/utils の cn() を使用する |
| 12 | Radix Select がクラッシュする | 値が空文字列 value="" | value="placeholder" を使用する |
| 13 | Tailwind のバージョンが間違っている | tailwindcss@^3 をインストールしている | tailwindcss@^4.1.0 と @tailwindcss/vite をインストールする |
| 14 | ピア依存関係が不足している | tailwindcss だけをインストールしている | clsx、tailwind-merge、@types/node もインストールする |
| 15 | ダークモードで壊れる | ライトモードだけをテストしている | ライト、ダーク、システム、および切り替え時の遷移をテストする |
| 16 | WCAG のコントラスト比を満たさない | 見た目には問題がない | 比率を確認する:通常のテキストは 4.5:1、大きな文字/UI は 3:1 |
| 17 | アニメーションのインポートでビルドに失敗する | tailwindcss-animate(非推奨)を使用している | tw-animate-css またはネイティブ CSS アニメーションを使用する |
| 18 | CSS の優先順位に問題がある | shadcn の初期化後に重複した @layer base がある | 単一の @layer base ブロックにまとめる |
コード例で見る注意点
#1 -- @layer base 内の :root
Tailwind v4 は @theme/@layer の外側にある CSS を削除しますが、:root は設定を保持するためにルートレベルに置く必要があります。これはセットアップで最もよくある失敗です。
誤り:
@layer base {
:root { --background: hsl(0 0% 100%); }
}
正しい例:
:root { --background: hsl(0 0% 100%); }
@layer base {
body { background-color: var(--background); }
}
#2 -- ネストされた @theme
Tailwind v4 はセレクター内の @theme をサポートしていません。:root/.dark の CSS 変数と、単一の @theme inline ブロックを使用してください。
誤り:
@theme { --color-primary: hsl(0 0% 0%); }
.dark { @theme { --color-primary: hsl(0 0% 100%); } }
正しい例:
:root { --primary: hsl(0 0% 0%); }
.dark { --primary: hsl(0 0% 100%); }
@theme inline { --color-primary: var(--primary); }
#3 -- hsl() の二重ラップ
変数にはすでに hsl() が含まれています。二重にラップすると hsl(hsl(...)) が生成されます。
誤り:background-color: hsl(var(--background));
正しい例:background-color: var(--background);
#4 -- tailwind.config.ts の色
Tailwind v4 は設定ファイル内の theme.extend.colors を完全に無視します。ファイルを削除するか、空のままにしてください。components.json で "config": "" を設定してください。
#5 -- @theme inline の欠落
@theme inline がないと、Tailwind は CSS 変数を認識できません。bg-background のようなユーティリティクラスは生成されません。
誤り:
:root { --background: hsl(0 0% 100%); }
/* No @theme inline block -- bg-background won't exist */
正しい例:
:root { --background: hsl(0 0% 100%); }
@theme inline { --color-background: var(--background); }
#7 -- PostCSS と Vite プラグイン
誤り:
export default defineConfig({
css: { postcss: './postcss.config.js' } // Old v3 way
})
正しい例:
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()] // v4 way
})
#8 -- パスエイリアス
tsconfig.app.json に追加します:
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] }
}
}
#11 -- クラスを結合する cn() ユーティリティ
誤り:className={`base ${isActive && 'active'}`}
正しい例:className={cn("base", isActive && "active")}
@/lib/utils の cn() は、Tailwind クラスを適切に結合し、重複を解消します。
#12 -- Radix Select の空の値
Radix UI Select では空文字列の値を使用できません。value="" の代わりに value="placeholder" を使用してください。
#14 -- 必須の依存関係
{
"dependencies": {
"tailwindcss": "^4.1.0",
"@tailwindcss/vite": "^4.1.0",
"clsx": "^2.1.1",
"tailwind-merge": "^3.3.1"
},
"devDependencies": {
"@types/node": "^24.0.0"
}
}
#17 -- tw-animate-css
Tailwind v4 では tailwindcss-animate は非推奨です。shadcn/ui のドキュメントには、まだ記載されている場合があります。ビルドの失敗やインポートエラーの原因になります。代わりに tw-animate-css または @tailwindcss/motion を使用してください。
#18 -- shadcn 初期化後の @layer base の重複
shadcn init は独自の @layer base ブロックを追加します。初期化を実行したら、すぐに src/index.css を確認し、重複するブロックがあれば1つにまとめてください。
誤り:
@layer base { body { background-color: var(--background); } }
@layer base { * { border-color: hsl(var(--border)); } } /* duplicate from shadcn */
正しい例:
@layer base {
* { border-color: var(--border); }
body { background-color: var(--background); color: var(--foreground); }
}
予防チェックリスト
-
tailwind.config.tsファイルがない(または空である) -
components.jsonに"config": ""が設定されている -
:root内のすべての色がhsl()でラップされている -
@theme inlineですべての変数がマッピングされている -
@layer baseが:rootを囲んでいない - テーマプロバイダーがアプリをラップしている
- ライト、ダーク、システムの各モードでテスト済みである
- すべてのテキストに十分なコントラストがある
ダークモードのテストチェックリスト
- ライトモードが正しく表示される
- ダークモードが正しく表示される
- システムモードが OS の設定に従う
- ページを更新してもテーマが保持される
- 切り替えコンポーネントに現在の状態が表示される
- すべてのテキストに適切なコントラストがある
- 読み込み時に誤ったテーマが一瞬表示されない
- シークレットモードでも動作する(適切なフォールバックがある)
アセットファイル
assets/ ディレクトリからコピーします:
index.css-- すべての色変数を含む完全な CSScomponents.json-- shadcn/ui v4 の設定vite.config.ts-- Vite + Tailwind プラグインtheme-provider.tsx-- ダークモードプロバイダーutils.ts--cn()ユーティリティ
参考ファイル
references/migration-guide.md-- v3 から v4 への移行ガイド
公式ドキュメント
- shadcn/ui Tailwind v4 ガイド:https://ui.shadcn.com/docs/tailwind-v4
- shadcn/ui ダークモード(Vite):https://ui.shadcn.com/docs/dark-mode/vite
- shadcn/ui テーマ設定:https://ui.shadcn.com/docs/theming
- Tailwind v4 ドキュメント:https://tailwindcss.com/docs
- Tailwind ダークモード:https://tailwindcss.com/docs/dark-mode