Claude CodeでDesign Tokensを実装する実践ガイド:FigmaからCSS変数、Tailwindまで
Claude CodeでDesign Tokensを設計し、CSS変数・Tailwind・Reactに展開する実装ガイド。
Design Tokensは「見た目の設定表」ではなく、UI変更の契約書
Design Tokens(デザイントークン)は、色・余白・文字サイズ・角丸・影のようなデザイン判断を、名前付きのデータとして管理する仕組みです。初心者向けに言うと、「ボタンの青」「カードの余白」「見出しの文字サイズ」をコードのあちこちに直接書かず、tokens.jsonのような1つの台帳にまとめる方法です。
Claude Codeと相性が良い理由は、トークンが「読めるデータ」だからです。Claude Codeに既存CSSを読ませ、重複している#2563ebや16pxを見つけ、意味のある名前に置き換え、Style DictionaryでCSS変数に変換し、TailwindやReactコンポーネントまでつなげられます。
ただし、Claude Codeに「いい感じにデザインシステム化して」と頼むと危険です。トークン名、置換範囲、アクセシビリティ基準、レビュー手順を決めないと、表面だけ整った大きな差分になります。この記事では、Figmaからコードへの受け渡し、raw tokenとsemantic tokenの違い、ダークモード、WCAGコントラスト、Style Dictionary、CSS変数、Tailwind設定、React Button、レビュー用プロンプトまで、コピペで試せる形でまとめます。
関連して、部品全体の設計はClaude Codeでデザインシステムを構築する実践ガイド、アクセシビリティ観点はClaude Codeでアクセシビリティ対応を効率化する方法も参照してください。
公式情報は、安定版のDesign Tokens Format Module 2025.10、Claude Code公式ドキュメント、Figma VariablesのPlugin API、Tailwindのtheme documentation、Style Dictionary docs、MDNのCSSカスタムプロパティ、WCAGのコントラスト解説を基準にします。
raw tokenとsemantic tokenを分ける
最初の落とし穴は、色名をそのままコンポーネントで使うことです。blue-600やgray-100のような値に近い名前をraw token、action-primary-bgやsurface-defaultのような用途を表す名前をsemantic tokenと呼びます。rawは素材、semanticは使い道です。
たとえばブランドカラーを青から緑に変えるとき、ボタンがcolor.blue.600を直接参照していると「青ではないのにblue」という名前が残ります。一方、ボタンがcolor.action.primary.bgを参照していれば、裏側の値だけ変えられます。
| 種類 | 例 | 使いどころ |
|---|---|---|
| raw token | color.blue.600, spacing.4 | 色階調や余白スケールの定義 |
| semantic token | color.action.primary.bg | ボタン、リンク、背景など用途の定義 |
| component token | button.primary.paddingX | 特定コンポーネントの細かい調整 |
小さなプロダクトならrawとsemanticだけで十分です。複数ブランド、複数プロダクト、細かい部品差がある場合だけcomponent tokenを増やします。最初から全コンポーネント専用トークンを作ると、管理する名前が増えすぎます。
Figma-like specをコード側の契約に落とす
Figma Variablesを使っていても、Claude Codeへ渡すときは「Figma-like spec(Figmaの意図をコードレビュー用に要約した仕様)」に変換すると安全です。これはFigmaを否定するためではなく、デザインツールの名前、プロダクト上の意味、コードの変更範囲を分けるためです。ここを分けないと、Blue / 600という見た目名がそのままReactに入り、後でブランド変更したときにriskが残ります。
{
"figmaSource": {
"file": "Marketing UI Kit",
"collection": "Brand v2",
"modes": ["light", "dark"]
},
"changeRequest": {
"type": "replace-token",
"from": "color.blue.600",
"to": "color.action.primary.bg",
"components": ["Button", "Link", "Card"]
},
"reviewRules": [
"Do not use raw color tokens in component CSS.",
"Keep focus and hover tokens explicit.",
"List affected use case and pitfall before editing files."
]
}
このJSONをClaude Codeに渡して「まず差分表だけ出して。ファイル編集はまだしない」と依頼すると、workflowの最初で人間が命名と影響範囲を確認できます。Masaが小規模LPで試したときも、先にこの仕様を置いたほうが、ボタンだけでなくリンク、カード、focus outlineまで同時に影響する変更を見落としにくくなりました。
実行できるtokens.json
次の例をtokens/tokens.jsonとして保存します。色、余白、タイポグラフィ、角丸、影、ライト/ダークのsemantic tokenを含めています。
{
"color": {
"blue": {
"50": { "$type": "color", "$value": "#eff6ff" },
"600": { "$type": "color", "$value": "#2563eb" },
"700": { "$type": "color", "$value": "#1d4ed8" }
},
"slate": {
"50": { "$type": "color", "$value": "#f8fafc" },
"100": { "$type": "color", "$value": "#f1f5f9" },
"700": { "$type": "color", "$value": "#334155" },
"900": { "$type": "color", "$value": "#0f172a" }
},
"white": { "$type": "color", "$value": "#ffffff" },
"focus": { "$type": "color", "$value": "#f59e0b" },
"surface": {
"default": { "$type": "color", "$value": "{color.white}" },
"muted": { "$type": "color", "$value": "{color.slate.50}" },
"inverse": { "$type": "color", "$value": "{color.slate.900}" }
},
"text": {
"default": { "$type": "color", "$value": "{color.slate.900}" },
"muted": { "$type": "color", "$value": "{color.slate.700}" },
"inverse": { "$type": "color", "$value": "{color.white}" }
},
"action": {
"primary": {
"bg": { "$type": "color", "$value": "{color.blue.600}" },
"bgHover": { "$type": "color", "$value": "{color.blue.700}" },
"text": { "$type": "color", "$value": "{color.white}" }
}
}
},
"dark": {
"color": {
"surface": {
"default": { "$type": "color", "$value": "{color.slate.900}" },
"muted": { "$type": "color", "$value": "{color.slate.700}" }
},
"text": {
"default": { "$type": "color", "$value": "{color.white}" },
"muted": { "$type": "color", "$value": "{color.slate.100}" }
},
"action": {
"primary": {
"bg": { "$type": "color", "$value": "{color.blue.50}" },
"bgHover": { "$type": "color", "$value": "{color.white}" },
"text": { "$type": "color", "$value": "{color.slate.900}" }
}
}
}
},
"space": {
"2": { "$type": "dimension", "$value": "0.5rem" },
"3": { "$type": "dimension", "$value": "0.75rem" },
"4": { "$type": "dimension", "$value": "1rem" },
"6": { "$type": "dimension", "$value": "1.5rem" }
},
"font": {
"size": {
"sm": { "$type": "dimension", "$value": "0.875rem" },
"base": { "$type": "dimension", "$value": "1rem" },
"lg": { "$type": "dimension", "$value": "1.125rem" }
},
"weight": {
"medium": { "$type": "fontWeight", "$value": "500" },
"bold": { "$type": "fontWeight", "$value": "700" }
}
},
"radius": {
"md": { "$type": "dimension", "$value": "0.5rem" },
"lg": { "$type": "dimension", "$value": "0.75rem" }
},
"shadow": {
"button": { "$type": "shadow", "$value": "0 1px 2px rgb(15 23 42 / 0.16)" }
}
}
ここで大事なのは、color.action.primary.bgのように「何のための色か」が分かる名前を残すことです。Claude Codeには「raw tokenを直接Reactコンポーネントに使わない」と明示すると、後のレビューがかなり楽になります。
Style DictionaryでCSS変数へ変換する
Style Dictionaryは、トークンJSONをCSS変数、TypeScript、iOS、Androidなどに変換するビルドツールです。まず最小構成を入れます。
npm install --save-dev style-dictionary
style-dictionary.config.jsを作成します。
export default {
source: ["tokens/tokens.json"],
hooks: {
formats: {
"css/variables-with-dark": ({ dictionary }) => {
const light = dictionary.allTokens
.filter((token) => !token.path.includes("dark"))
.map((token) => ` --${token.name}: ${token.value};`)
.join("\n");
const dark = dictionary.allTokens
.filter((token) => token.path[0] === "dark")
.map((token) => ` --${token.path.slice(1).join("-")}: ${token.value};`)
.join("\n");
return `:root {\n${light}\n}\n\n[data-theme="dark"] {\n${dark}\n}\n`;
}
}
},
platforms: {
css: {
transformGroup: "css",
buildPath: "src/styles/",
files: [{ destination: "tokens.css", format: "css/variables-with-dark" }]
}
}
};
package.jsonにはビルドコマンドを足します。
{
"scripts": {
"tokens:build": "style-dictionary build --config style-dictionary.config.js"
}
}
実行すると、src/styles/tokens.cssのようなCSSが生成されます。
:root {
--color-blue-50: #eff6ff;
--color-blue-600: #2563eb;
--color-action-primary-bg: #2563eb;
--color-action-primary-bg-hover: #1d4ed8;
--color-action-primary-text: #ffffff;
--space-3: 0.75rem;
--space-4: 1rem;
--font-size-base: 1rem;
--font-weight-bold: 700;
--radius-md: 0.5rem;
--shadow-button: 0 1px 2px rgb(15 23 42 / 0.16);
}
[data-theme="dark"] {
--color-surface-default: #0f172a;
--color-text-default: #ffffff;
--color-action-primary-bg: #eff6ff;
--color-action-primary-text: #0f172a;
}
CSSカスタムプロパティ(CSS変数)は、var(--color-action-primary-bg)のように参照できるブラウザ標準の仕組みです。ダークモードではdata-theme="dark"をhtmlやbodyに付けるだけで、同じコンポーネントが別の値を使います。
Tailwind configに接続する
Tailwindを使う場合も、トークンから生成したCSS変数を参照させます。こうすると、Tailwindのクラス名は便利に使いつつ、値の出どころはtokens.jsonに固定できます。
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{ts,tsx,js,jsx,mdx}"],
theme: {
extend: {
colors: {
surface: {
DEFAULT: "var(--color-surface-default)",
muted: "var(--color-surface-muted)"
},
text: {
DEFAULT: "var(--color-text-default)",
muted: "var(--color-text-muted)",
inverse: "var(--color-text-inverse)"
},
action: {
primary: "var(--color-action-primary-bg)",
"primary-hover": "var(--color-action-primary-bg-hover)"
}
},
spacing: {
3: "var(--space-3)",
4: "var(--space-4)",
6: "var(--space-6)"
},
borderRadius: {
md: "var(--radius-md)",
lg: "var(--radius-lg)"
},
boxShadow: {
button: "var(--shadow-button)"
}
}
}
};
React Buttonで使う
次はトークンを消費するButtonです。クラスでもCSS Modulesでも構いませんが、ここではCSS変数が見えるように素のCSSで書きます。
import "./Button.css";
type ButtonProps = {
children: React.ReactNode;
onClick?: () => void;
disabled?: boolean;
};
export function Button({ children, onClick, disabled = false }: ButtonProps) {
return (
<button className="Button" onClick={onClick} disabled={disabled}>
{children}
</button>
);
}
.Button {
background: var(--color-action-primary-bg);
border: 0;
border-radius: var(--radius-md);
box-shadow: var(--shadow-button);
color: var(--color-action-primary-text);
cursor: pointer;
font-size: var(--font-size-base);
font-weight: var(--font-weight-bold);
padding: var(--space-3) var(--space-4);
}
.Button:hover:not(:disabled) {
background: var(--color-action-primary-bg-hover);
}
.Button:focus-visible {
outline: 3px solid var(--color-focus);
outline-offset: 2px;
}
.Button:disabled {
cursor: not-allowed;
opacity: 0.55;
}
アクセシビリティでは、通常テキストのコントラスト比が4.5:1以上になるよう確認します。Claude Codeに「color.action.primary.bgとcolor.action.primary.textのコントラストを計算して」と頼むだけでなく、最終的にはブラウザ、Storybook、axe、手動確認を組み合わせます。
4つの実用ユースケース
1つ目は、Figmaからコードへの受け渡しです。Figma Variablesやデザイナーの命名をそのまま正解にせず、Claude Codeに「現在のtokens.jsonとの差分」「既存コンポーネントへの影響」「名前が用途を表しているか」をレビューさせます。Figmaは設計入力、tokens.jsonはコード側の契約書、と分けると衝突が減ります。
2つ目は、ダークモードの追加です。既存CSSを丸ごと複製するのではなく、semantic tokenだけを上書きします。surface.default、text.default、action.primary.bgのような用途単位で変えると、コンポーネントの実装は変えずにテーマを増やせます。
3つ目は、ブランド刷新やLP改善です。広告用LPだけ色や余白を変えたいとき、各CSSを手で直すとドリフト(同じはずの値が少しずつズレる状態)が起きます。トークンを変更し、ビルドし、Storybookやスクリーンショットテストで差分を見る流れにすれば、変更の範囲が説明できます。
4つ目は、レビューの標準化です。Pull Requestで「この青は合っている?」と議論する代わりに、「raw tokenを直接使っていないか」「semantic token名は用途を表すか」「WCAGコントラストを満たすか」をチェック項目にします。Claude Codeはこの反復レビューが得意です。
具体的な落とし穴
よくある失敗は、最初にトークンを細かくしすぎることです。button-primary-large-desktop-padding-leftのような名前を大量に作ると、誰も覚えられません。まずは色、余白、文字、角丸、影の基本スケールとsemantic tokenから始めます。
次の失敗は、命名に見た目だけを入れることです。blueButtonよりprimaryAction、grayTextよりtextMutedのほうが長く使えます。色が変わっても用途名が残るからです。
三つ目は、生成物を手で編集することです。src/styles/tokens.cssはビルド結果なので、直接修正してはいけません。変更は必ずtokens/tokens.jsonに戻し、npm run tokens:buildで再生成します。
四つ目は、コントラストを後回しにすることです。ダークモードやhover色を追加した後に見ると、修正範囲が広がります。Claude Codeへの依頼に「通常、hover、disabled、focus、dark themeのコントラストを確認」と入れておくと、レビュー漏れを減らせます。
レビュー checklist
-
tokens/tokens.jsonが唯一の編集元で、生成されたsrc/styles/tokens.cssを手で直していない - Button、Link、Cardの3つのuse caseで、light/dark、hover、disabled、focusを確認した
- ReactやTailwindのコードがraw tokenではなくsemantic tokenを参照している
- Figma-like specの変更理由、影響コンポーネント、pitfall、riskがPR本文に書かれている
- WCAG 2.2 AAの通常テキスト4.5:1、UI部品3:1のコントラストを確認した
- Claude Codeが提案したworkflowをそのまま通さず、人間が命名とブランド意図をレビューした
Claude Codeに依頼するレビュー用プロンプト
以下をそのまま使えます。対象ファイルはプロジェクトに合わせて調整してください。
Design token review task:
- Read tokens/tokens.json, style-dictionary.config.js, src/styles/tokens.css, tailwind.config.js, and src/components/Button.tsx.
- Check that components use semantic tokens, not raw color tokens.
- Verify light and dark theme values for button, surface, and text tokens.
- Flag any generated CSS file that was edited manually.
- Check WCAG 2.2 AA contrast for normal text and button text.
- Suggest the smallest safe diff. Do not rename tokens unless you list every affected component.
- After changes, run npm run tokens:build and the focused component tests.
Claude Codeには、作業範囲を狭く、確認コマンドを明示し、レビュー観点を箇条書きで渡します。これだけで「見た目の修正」から「再現できる変更管理」に変わります。
まとめとCTA
Design Tokensは、UIをきれいにするためだけの道具ではありません。Figma、CSS、Tailwind、React、レビュー、アクセシビリティを同じ言葉でつなぐための運用基盤です。Claude Codeを使うなら、tokens.jsonを中心に置き、Style Dictionaryで生成し、コンポーネントではsemantic tokenだけを使い、PRでドリフトとコントラストを確認する流れを作るのが現実的です。
次にやるなら、既存プロジェクトからボタン、リンク、カードの3部品だけを選び、色と余白をsemantic tokenへ置き換えてください。より広い設計に進む場合はデザインシステム構築ガイドを読み、個人で使うテンプレートやチェックリストはClaudeCodeLabのプロダクトを確認してください。チーム導入やレビュー設計が必要ならClaudeCodeLabのトレーニング・相談が次の選択肢です。
実際に試した結果
この記事で紹介した内容を実際に試した結果、tokens.jsonからCSS変数を生成し、Buttonの背景色・文字色・focus outlineを切り替える流れは小さなReact環境で再現できました。特に効果があったのは、先にFigma-like specで変更意図を書き、Claude Codeに影響表を出させてから編集させる順番です。実務では、ここにStorybookの状態確認、axeによるアクセシビリティテスト、PRでのClaude Codeレビューを足すと、デザイン変更の再現性が大きく上がります。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
ObsidianメモをCLAUDE.mdに変えるClaude Code運用: 文脈を毎回説明しない仕組み
Obsidianの作業メモからCLAUDE.md用の運用ノートを作り、Claude Codeに安定した文脈を渡す方法。
Claude Code Revenue CTA Routing: 記事からPDF、Gumroad、相談へ送る設計
PVだけで終わらせず、読者の状態に合わせて無料PDF、Gumroad教材、導入相談へ分岐するCTA設計です。
Claude Codeチーム引き継ぎルール: レビュー、権限、収益導線まで渡す実務手順
Claude Codeの作業をチームで渡すための証拠、権限、ロールバック、無料PDF/Gumroad/相談導線の実務ルール。