Pourquoi les design tokens changent la façon d’écrire une interface
Quand une application grandit, les petits choix visuels se multiplient : #2563eb ici, 12px là, [border](/articles/css-style-page-web)-radius: 8px dans un composant, puis 10px dans un autre. Au début, cela semble anodin. Après quelques mois, l’interface devient difficile à faire évoluer : changer la couleur principale demande une recherche globale, harmoniser les espacements devient subjectif, et chaque nouveau composant réinvente une partie du système graphique.
Les design tokens permettent de résoudre ce problème en donnant un nom métier aux décisions de design. Au lieu d’écrire une valeur brute partout, on utilise une variable comme --color-primary, --space-4 ou --radius-md. Ces tokens deviennent le vocabulaire commun entre design, CSS, composants React ou Vue, documentation et tests visuels.
Ils complètent très bien une architecture CSS moderne. Par exemple, vous pouvez les combiner avec les cascade layers CSS pour contrôler leur priorité, ou avec les container queries CSS pour créer des composants adaptatifs sans dupliquer les valeurs de mise en page.
Qu’est-ce qu’un design token ?
Un design token est une valeur nommée qui représente une décision de design. Il ne s’agit pas seulement d’une variable technique, mais d’un contrat entre l’intention visuelle et son implémentation.
Par exemple, cette couleur brute ne raconte pas grand-chose :
.button {
background: #2563eb;
}
Avec un token, l’intention devient plus claire :
.button {
background: var(--color-action-primary);
}
Le nom indique que cette couleur sert à représenter une action principale. Si la marque change de bleu, ou si le mode sombre nécessite une autre valeur, le composant n’a pas besoin d’être modifié.
On distingue souvent plusieurs niveaux de tokens :
- les tokens primitifs, proches des valeurs brutes, comme
--blue-600ou--space-4; - les tokens sémantiques, liés à un usage, comme
--color-text-mutedou--color-background-surface; - les tokens de composants, plus spécifiques, comme
--button-primary-background.
Dans la plupart des projets web, les tokens sémantiques sont les plus importants, car ils rendent le code plus stable face aux changements graphiques.
Définir une première base de tokens CSS
Un bon point de départ consiste à déclarer les tokens globaux dans :root. Ils seront disponibles dans toute l’application.
:root {
--color-brand-500: #2563eb;
--color-brand-700: #1d4ed8;
--color-background-page: #ffffff;
--color-background-surface: #f8fafc;
--color-text-primary: #0f172a;
--color-text-muted: #64748b;
--color-border-subtle: #e2e8f0;
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-6: 1.5rem;
--space-8: 2rem;
--radius-sm: 0.25rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-md: 1rem;
--font-size-lg: 1.125rem;
}
Ces tokens ne doivent pas forcément couvrir toute l’interface dès le premier jour. Il vaut mieux commencer avec une base compacte, réellement utilisée, plutôt qu’un catalogue trop vaste que personne ne comprend.
Utiliser les tokens dans un composant
Prenons une carte d’article simple. Sans tokens, elle risque d’accumuler des valeurs arbitraires. Avec tokens, elle devient plus cohérente avec le reste de l’interface.
.article-card {
padding: var(--space-6);
border: 1px solid var(--color-border-subtle);
border-radius: var(--radius-lg);
background: var(--color-background-surface);
}
.article-card__title {
margin: 0 0 var(--space-2);
color: var(--color-text-primary);
font-size: var(--font-size-lg);
}
.article-card__description {
margin: 0;
color: var(--color-text-muted);
font-size: var(--font-size-md);
}
Le bénéfice n’est pas seulement esthétique. Le composant devient plus facile à relire : les espacements, couleurs et tailles appartiennent à un système partagé. Cela réduit les débats inutiles du type « 14px ou 15px ? » et accélère la production d’interfaces homogènes.
Gérer le mode sombre avec des tokens sémantiques
Les tokens sont particulièrement utiles pour le mode sombre. L’erreur fréquente consiste à inverser directement des couleurs primitives. Or un bleu, un gris ou un rouge n’ont pas toujours le même rôle selon le thème.
Avec des tokens sémantiques, on redéfinit les usages, pas les composants.
:root {
--color-background-page: #ffffff;
--color-background-surface: #f8fafc;
--color-text-primary: #0f172a;
--color-text-muted: #64748b;
--color-border-subtle: #e2e8f0;
}
[data-theme="dark"] {
--color-background-page: #020617;
--color-background-surface: #0f172a;
--color-text-primary: #f8fafc;
--color-text-muted: #94a3b8;
--color-border-subtle: #1e293b;
}
Le composant .article-card n’a pas besoin de connaître le thème actif. Il continue d’utiliser --color-background-surface et --color-text-primary. C’est le conteneur applicatif qui décide de la valeur réelle.
<body data-theme="dark">
<article class="article-card">
<h2 class="article-card__title">Comprendre les design tokens</h2>
<p class="article-card__description">Une approche robuste pour structurer votre interface.</p>
</article>
</body>
Cette séparation est essentielle dans un design system : les composants consomment des intentions, tandis que les thèmes fournissent les valeurs.
Partager les tokens avec TypeScript
Dans une application moderne, les tokens ne servent pas uniquement au CSS. On peut aussi en avoir besoin dans TypeScript : pour configurer un graphique, générer une documentation, typer des variantes de composants ou synchroniser un thème avec une librairie UI.
Une approche simple consiste à définir une source TypeScript, puis à générer ou exposer les valeurs nécessaires.
export const tokens = {
colors: {
backgroundPage: 'var(--color-background-page)',
backgroundSurface: 'var(--color-background-surface)',
textPrimary: 'var(--color-text-primary)',
textMuted: 'var(--color-text-muted)',
actionPrimary: 'var(--color-brand-500)'
},
spacing: {
1: 'var(--space-1)',
2: 'var(--space-2)',
4: 'var(--space-4)',
6: 'var(--space-6)'
},
radius: {
sm: 'var(--radius-sm)',
md: 'var(--radius-md)',
lg: 'var(--radius-lg)'
}
} as const;
export type ColorToken = keyof typeof tokens.colors;
export type SpacingToken = keyof typeof tokens.spacing;
On peut ensuite utiliser ces types dans un composant React.
type BadgeProps = {
children: React.ReactNode;
tone?: 'neutral' | 'brand';
};
export function Badge({ children, tone = 'neutral' }: BadgeProps) {
return <span className={`badge badge--${tone}`}>{children}</span>;
}
.badge {
display: inline-flex;
align-items: center;
padding: var(--space-1) var(--space-2);
border-radius: var(--radius-md);
font-size: var(--font-size-sm);
}
.badge--neutral {
color: var(--color-text-muted);
background: var(--color-background-surface);
}
.badge--brand {
color: white;
background: var(--color-brand-500);
}
L’objectif n’est pas de tout contrôler depuis TypeScript. Le CSS reste l’endroit naturel pour exprimer le rendu visuel. TypeScript intervient surtout pour typer les options, documenter les variantes et éviter les valeurs impossibles.
Éviter les tokens trop abstraits
Un mauvais token peut rendre l’interface plus confuse. Par exemple, --color-blue, --size-normal ou --spacing-default sont parfois trop vagues. Le nom doit aider à comprendre l’usage.
Comparez ces deux versions :
/* Trop vague */
.alert {
color: var(--color-red);
padding: var(--spacing-default);
}
/* Plus intentionnel */
.alert {
color: var(--color-feedback-danger-text);
padding: var(--space-4);
}
Le second exemple distingue mieux la nature du token. La couleur est liée à un message d’erreur ou de danger. L’espacement, lui, peut rester sur une échelle primitive, car son rôle est moins contextuel.
Il ne faut pas chercher une sémantique absolue pour chaque valeur. Une bonne règle pratique consiste à utiliser des tokens sémantiques pour les couleurs et les usages métier, puis des échelles primitives pour les espacements, tailles et rayons.
Organiser les tokens dans un projet réel
Dans un projet frontend, vous pouvez séparer les tokens en plusieurs fichiers :
src/
styles/
tokens.css
base.css
components.css
tokens/
index.ts
Le fichier tokens.[css](/articles/css-style-page-web) contient les variables CSS globales. Le fichier base.[css](/articles/css-style-page-web) applique les styles de fond, de typographie et de document. Les composants consomment ensuite ces tokens sans redéfinir de valeurs arbitraires.
body {
margin: 0;
color: var(--color-text-primary);
background: var(--color-background-page);
font-family: system-ui, sans-serif;
}
a {
color: var(--color-brand-700);
}
Pour les projets plus avancés, les tokens peuvent être stockés dans un fichier JSON, puis transformés vers CSS, TypeScript, documentation ou outils de design. Le format du Design Tokens Community Group donne une base intéressante pour réfléchir à cette normalisation, même si un projet n’a pas toujours besoin d’une chaîne de génération complexe.
Mesurer le vrai bénéfice
Les design tokens ne sont pas une couche de décoration. Ils améliorent la maintenance, la cohérence visuelle et la collaboration. Leur intérêt devient particulièrement visible quand plusieurs développeurs interviennent sur la même interface, quand un mode sombre est ajouté, ou quand une refonte graphique doit être menée sans réécrire tous les composants.
Ils s’intègrent aussi dans une démarche de performance et de qualité frontend. Par exemple, une interface cohérente limite les variantes inutiles de composants, tandis qu’une bonne architecture CSS évite les surcharges répétées. Dans la même logique, la performance visuelle dépend aussi d’autres choix, comme l’optimisation des images web ou la séparation des calculs coûteux avec les Web Workers en JavaScript.
Conclusion
Mettre en place des design tokens, ce n’est pas ajouter une convention de nommage pour faire joli. C’est construire une couche de décision stable entre le design et le code. Les composants deviennent plus lisibles, les thèmes plus simples à gérer, et les évolutions graphiques moins risquées.
Commencez petit : quelques couleurs sémantiques, une échelle d’espacement, trois rayons, deux ou trois tailles de texte. Utilisez-les systématiquement dans vos composants. Ensuite seulement, vous pourrez industrialiser avec TypeScript, JSON, génération automatique ou documentation de design system. La valeur des tokens ne vient pas de leur nombre, mais de leur adoption réelle dans l’interface.