Pourquoi un design system change tout
Sans design system, chaque page d'un site devient un archipel : des boutons légèrement différents d'une section à l'autre, des espacements incohérents, des couleurs qui varient à chaque composant. Le design system est la réponse systématique à ce problème.
Un bon design system c'est : un langage commun entre designers et développeurs, une base de composants testés et accessibles, et une documentation vivante.
La pyramide d'un design system
[Patterns]
Connexions de formulaire
Tableaux de données, cards
[Composants]
Button, Input, Modal, Toast
Badge, Dropdown, Tabs, Alert
[Fondations]
Couleurs, Typographie, Espacement
Ombres, Bordures, Animation, Icônes
[Design Tokens]
Variables nommées sémantiquement
(connectées Figma ↔ Code)
Les design tokens — le lien Figma ↔ Code
Les tokens sont des variables nommées qui représentent les décisions de design :
// tokens.json (source de vérité)
{
"color": {
"primitive": {
"blue-500": { "value": "#3b82f6" },
"blue-600": { "value": "#2563eb" },
"gray-100": { "value": "#f3f4f6" },
"gray-900": { "value": "#111827" }
},
"semantic": {
"primary": { "value": "{color.primitive.blue-500}" },
"primary-hover": { "value": "{color.primitive.blue-600}" },
"background": {
"default": { "value": "#ffffff" },
"subtle": { "value": "{color.primitive.gray-100}" }
},
"text": {
"default": { "value": "{color.primitive.gray-900}" }
}
}
},
"spacing": {
"xs": { "value": "4px" },
"sm": { "value": "8px" },
"md": { "value": "16px" },
"lg": { "value": "24px" },
"xl": { "value": "32px" },
"2xl": { "value": "48px" }
},
"radius": {
"sm": { "value": "4px" },
"md": { "value": "8px" },
"lg": { "value": "12px" }
}
}
Avec Style Dictionary, transformez ces tokens en variables CSS, SCSS, ou JS :
npm install -D style-dictionary
// build-tokens.js
const StyleDictionary = require('style-dictionary');
StyleDictionary.extend({
source: ['tokens.json'],
platforms: {
css: {
transformGroup: 'css',
files: [{
destination: 'tokens.css',
format: 'css/variables',
options: { outputReferences: true }
}]
}
}
}).buildAllPlatforms();
Résultat :
:root {
--color-primitive-blue-500: #3b82f6;
--color-semantic-primary: var(--color-primitive-blue-500);
--spacing-md: 16px;
--radius-md: 8px;
}
Construire un composant Button robuste
<!-- HTML sémantique avec variantes par attributs data -->
<button
class="btn"
data-variant="primary"
data-size="md"
type="button">
<span class="btn-icon btn-icon-left" aria-hidden="true">
<svg>...</svg>
</span>
<span class="btn-label">Envoyer</span>
</button>
.btn {
/* Structure */
display: inline-flex;
align-items: center;
gap: var(--spacing-xs);
border: 2px solid transparent;
cursor: pointer;
font-weight: 600;
transition: background 150ms, border-color 150ms, color 150ms;
/* Focus accessible */
outline: none;
}
.btn:focus-visible {
box-shadow: 0 0 0 3px var(--color-semantic-primary),
0 0 0 5px rgba(59,130,246,0.3);
}
/* Tailles */
.btn[data-size="sm"] { padding: 6px 14px; font-size: 13px; border-radius: var(--radius-sm); }
.btn[data-size="md"] { padding: 10px 20px; font-size: 14px; border-radius: var(--radius-md); }
.btn[data-size="lg"] { padding: 14px 28px; font-size: 16px; border-radius: var(--radius-md); }
/* Variantes */
.btn[data-variant="primary"] {
background: var(--color-semantic-primary);
color: white;
}
.btn[data-variant="primary"]:hover {
background: var(--color-semantic-primary-hover);
}
.btn[data-variant="secondary"] {
background: transparent;
border-color: var(--color-semantic-primary);
color: var(--color-semantic-primary);
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
Documentation avec Storybook
Storybook est le standard pour documenter les composants de façon interactive :
npx storybook@latest init
// Button.stories.js
export default {
title: 'Composants/Button',
component: Button,
parameters: {
docs: { description: { component: 'Bouton principal. Utiliser pour les CTAs primaires.' } }
},
argTypes: {
variant: { control: 'select', options: ['primary', 'secondary', 'danger'] },
size: { control: 'select', options: ['sm', 'md', 'lg'] },
disabled: { control: 'boolean' }
}
};
export const Primary = { args: { variant: 'primary', label: 'Envoyer' } };
export const Secondary = { args: { variant: 'secondary', label: 'Annuler' } };
export const Loading = { args: { variant: 'primary', loading: true, label: 'Chargement...' } };
Gouvernance et évolution
Un design system qui n'évolue pas meurt. Définissez dès le départ :
Processus de contribution :
- Besoin identifié → issue dans le repo du design system
- Discussion en équipe (est-ce vraiment un composant générique ?)
- Maquette Figma + code en parallèle
- Review croisée designer/développeur
- Documentation + Storybook story
- Release avec changelog
- PATCH (1.0.x) : correction de bugs, micro-ajustements
- MINOR (1.x.0) : nouveau composant ou variante, rétro-compatible
- MAJOR (x.0.0) : breaking change (renommage de token, API de composant)
Pour aller plus loin : Design Systems Handbook — référence gratuite de InVision.
Un design system vivant, pas un musée
Le plus grand risque d'un design system est de devenir obsolète. Prévoyez des sessions de revue trimestrielles, maintenez un changelog visible, et formez les nouveaux arrivants dès le premier jour. Un design system adopté activement divise le temps d'intégration par deux sur la durée.