Design Tokens mit Claude Code: von Figma zu CSS-Variablen, Tailwind und React
Design Tokens mit Claude Code, Style Dictionary, CSS-Variablen, Tailwind und React umsetzen.
Design Tokens sind ein Vertrag für UI-Änderungen
Design Tokens speichern Designentscheidungen als benannte Daten: Farben, Abstände, Typografie, Radien, Schatten und Zustände. Statt #2563eb, 16px oder 0.5rem in vielen Komponenten zu wiederholen, liegt die Quelle in tokens.json. Daraus erzeugst du CSS-Variablen, Tailwind-Konfiguration und Werte für React-Komponenten.
Claude Code passt gut zu diesem Arbeitsablauf, weil Token-Arbeit prüfbar ist. Es kann vorhandenes CSS lesen, hart codierte Werte finden, semantische Namen vorschlagen, Komponenten ändern, den Build ausführen und den Diff zusammenfassen. Ein vager Prompt wie “mach die UI konsistent” ist riskant. Besser sind klare Grenzen: Token-Datei, betroffene Komponenten, Kontrastregeln und auszuführende Befehle.
Als Ergänzung eignen sich Design-Systeme mit Claude Code und Barrierefreiheit mit Claude Code. Offizielle Referenzen sind das stabile Design Tokens Format Module 2025.10, die Claude Code Docs, die Figma Variables Plugin API, die Tailwind Theme Docs, Style Dictionary, MDN CSS Custom Properties und WCAG Kontrast.
Raw Tokens und Semantic Tokens
Raw Tokens beschreiben das Material: color.blue.600, space.4, font.size.base. Semantic Tokens beschreiben die Absicht: color.action.primary.bg, color.text.muted, color.surface.default. Component Tokens beschreiben lokale Regeln wie button.primary.paddingX.
| Typ | Beispiel | Einsatz |
|---|---|---|
| Raw | color.blue.600 | Paletten, Spacing-Skalen, Typografie-Skalen |
| Semantic | color.action.primary.bg | Produktbedeutung, Themes, Dark Mode |
| Component | button.primary.paddingX | Stabile komponentenspezifische Ausnahmen |
Starte mit raw und semantic. Wenn ein Button direkt color.blue.600 nutzt, bleibt der Name nach einem Rebranding schnell falsch. Mit color.action.primary.bg kann sich der Wert ändern, während die Bedeutung stabil bleibt.
Figma-like Spec als Code-Vertrag
Figma Variables sind hilfreich, aber Claude Code sollte einen prüfbaren Handoff bekommen, keinen ungefilterten Namensexport. Eine Figma-like Spec nennt Quelldatei, Modi, gewünschte Änderung, betroffene Komponenten und Review-Regeln. So sinkt das risk, dass ein visueller Name wie Blue / 600 in React landet, obwohl der Produktzweck color.action.primary.bg ist.
{
"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."
]
}
Lass Claude Code zuerst eine Impact-Tabelle ausgeben und erst nach menschlichem Review Dateien ändern. Dieser workflow verhindert den typischen pitfall, dass ein einzelner Farbwechsel Button, Link, Card und Focus Outline gleichzeitig verändert.
Ausführbare tokens.json
Speichere diese Datei als tokens/tokens.json:
{
"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)" }
}
}
CSS-Variablen mit Style Dictionary erzeugen
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" }]
}
}
};
Script:
{
"scripts": {
"tokens:build": "style-dictionary build --config style-dictionary.config.js"
}
}
Erwartete CSS-Ausgabe:
:root {
--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;
}
Tailwind und React Button
/** @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)" }
}
}
};
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;
}
Praxisfälle, Fallstricke und Review
Der erste Praxisfall ist der Figma-to-Code-Handoff. Figma Variables sind ein guter Input, aber tokens.json bleibt der überprüfte Vertrag im Code. Claude Code kann Export und vorhandene Tokens vergleichen und neue, entfernte oder umbenannte Werte samt Komponentenwirkung auflisten.
Der zweite Fall ist Dark Mode. Kopiere nicht jedes Component Stylesheet. Überschreibe semantische Tokens wie surface, text und action.
Der dritte Fall ist ein Rebranding oder eine Landing-Page-Überarbeitung. Token-Builds und Storybook-Screenshots verhindern, dass Farben und Abstände langsam auseinanderlaufen.
Häufige Fehler sind zu viele Component Tokens am ersten Tag, Namen nach Aussehen statt Absicht (blueButton statt primaryAction), manuelles Bearbeiten von generiertem tokens.css und zu spätes Prüfen des Kontrasts. Für normalen Text verlangt WCAG AA mindestens 4,5:1.
Review checklist:
-
tokens/tokens.jsonist die einzige bearbeitete Quelle; generiertes CSS wurde nicht manuell geändert. - Button, Link und Card wurden für light, dark, hover, disabled und focus geprüft.
- React und Tailwind nutzen Semantic Tokens statt Raw Palette Tokens.
- PR beschreibt Figma-like spec, use case, pitfall, risk und workflow.
- Kontrast nach WCAG 2.2 AA wurde für Text und interaktive Zustände geprüft.
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.
Fazit
Ein robuster Ablauf ist: tokens.json pflegen, CSS-Variablen mit Style Dictionary generieren, in Tailwind abbilden, in Komponenten nur Semantic Tokens verwenden und jeden PR auf Drift und Kontrast prüfen. Ich habe den Beispielpfad mit generierten CSS-Variablen und einem React Button für Farbe, Spacing, Radius, Shadow und Focus Outline nachvollzogen. Für wiederverwendbare Prompts und Checklisten eignen sich ClaudeCodeLab Produkte. Für Produktion und Team-Rollouts ergänze Storybook, axe, visuelle Reviews und ClaudeCodeLab Training und Beratung.
Kostenloses PDF: Claude-Code-Cheatsheet
E-Mail eintragen und eine Seite mit Befehlen, Review-Gewohnheiten und sicheren Workflows herunterladen.
Wir schützen Ihre Daten und senden keinen Spam.
Über den Autor
Masa
Engineer für praktische Claude-Code-Workflows und Team-Einführung.
Ähnliche Artikel
Claude Code Workflow von Obsidian zu CLAUDE.md
Obsidian-Arbeitsnotizen in CLAUDE.md-Betriebsnotizen verwandeln und Kontext nicht ständig neu erklären.
Claude Code Revenue CTA Routing: Artikel zu PDF, Gumroad und Beratung führen
Ein Claude-Code-Ablauf, der Leser nach Absicht zu Gratis-PDF, Gumroad oder Beratung führt.
Claude-Code-Team-Handoff-Regeln: Belege, Berechtigungen, Rollback und Umsatzpfade
Ein praktisches Claude-Code-Handoff für Review-Belege, Berechtigungen, Rollback, Gratis-PDF, Gumroad und Beratung.