Un design system n'est pas une bibliothèque de composants d'interface utilisateur : c'est le contrat partagé entre conception et développement qui garantissent la cohérence visuelle, comportementale et d'accessibilité dans tous produits d'une organisation. En construire un dans Angular signifie assembler quatre pièces qui ils sont souvent abordés séparément et mal : composants réutilisables avec des API stables, générateurs schémas qui réduisent les frictions d'adoption, Storybook comment environnement de développement et de documentation isolé, et un processus de publication sur npm fiable avec le versioning sémantique.
Les avantages mesurables d'un système de conception mature sont concrets : moins de temps passé à réinventer composants déjà existants, moins de bugs d'interface utilisateur dus à des implémentations divergentes du même modèle, e une surface de test plus petite car la logique des composants partagés n'est validée qu'une seule fois temps plutôt que dans chaque application qui les consomme. Le principal risque, si la conception le système n’a pas de gouvernance claire, c’est exactement le contraire : une bibliothèque qui devient un goulot d’étranglement car chaque équipe doit attendre une version centralisée pour chaque petit changement.
Architecture de la bibliothèque : Monorepo vs Repo séparé
La première décision architecturale détermine tout le reste du flux de travail. Un monorepo (géré avec Nx ou espace de travail Angular CLI multi-projets) contient des systèmes de conception et des applications consommateur dans le même référentiel : les modifications sont instantanément testées par rapport à des applications réelles sans publier une version intermédiaire, mais le référentiel s'agrandit et nécessite des outils pour les builds incrémentielles. Un repo distinct pour le système de conception impose une discipline de gestion des versions plus rigoureuse. d'emblée, cela oblige à penser l'API du composant comme un véritable marché public, mais cela introduit latence entre un changement et sa disponibilité chez les consommateurs.
Critères de choix
| Critère | Monorepo | Repo séparé |
|---|---|---|
| Nombre d'équipes de consommateurs | 1-2 équipes | 3+ équipes indépendantes |
| Vitesse d'itération | Élevé, retour immédiat | Plus lent, nécessite une publication |
| Discipline API requise | Faible (vous pouvez voir immédiatement si quelque chose se casse) | Élevé (l'API est un contrat public) |
| Complexité des outils | Moyenne/Élevée (Nx, cache de build) | Faible (version standard Angular CLI) |
Pour la convention de dénomination, adoptez une portée npm dédiée (par exemple @company/ui) dès le premier
composant, et appliquez strictement Semantic Versioning : correctif pour les corrections de bugs sans
Modifications de l'API, mineures pour les nouveaux composants ou les accessoires facultatifs, majeures pour toute modification radicale des accessoires
existant, en supprimant des composants ou en modifiant le comportement par défaut.
Conception de composants : accessibilité, thématisation et API
Chaque composant du système de conception doit suivre des règles plus strictes qu'un composant d'application n'importe lequel, car son rayon d'impact s'étend à l'ensemble de l'organisation, et non à une seule fonctionnalité.
// Component design: standalone, OnPush, API tipizzata con Signal-based inputs
@Component({
selector: 'ds-button',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
@if (loading()) { }
`,
})
export class DsButtonComponent {
variant = input<'primary' | 'secondary' | 'danger'>('primary');
disabled = input(false);
loading = input(false);
pressed = output();
protected variantClass = computed(() => `ds-btn ds-btn--${this.variant()}`);
}
Trois règles non négociables pour chaque composant public : OnPush obligatoire (un système de conception avec détection des changements (par défaut propage les ralentissements à chaque application qui le consomme), API basée sur les entrées/sorties de signal au lieu des propriétés mutables exposées directement, et zéro dépendance sur les styles globaux de l'application hôte — chaque composant doit être visuellement correct même sur une page blanche sans CSS externe, sinon la thématisation devient impossible à garantir.
Schémas : générateurs personnalisés pour réduire les frictions d'adoption
Une personnalisation schématique permet aux équipes de consommateurs d'étayer l'utilisation correcte d'un composant avec un commande unique, au lieu de copier-coller des exemples de la documentation (ce qui inévitablement devenir obsolète).
// schematics/add-form-field/index.ts
export function addFormField(options: AddFormFieldOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
const componentPath = `${options.path}/${options.name}.component.ts`;
const content = `
import { Component, input } from '@angular/core';
import { DsInputComponent } from '@azienda/ui/input';
@Component({
selector: 'app-${options.name}',
standalone: true,
imports: [DsInputComponent],
template: \`\`,
})
export class ${strings.classify(options.name)}Component {
label = input.required();
control = input.required();
}
`;
tree.create(componentPath, content);
context.logger.info(`✅ Creato ${componentPath}`);
return tree;
};
}
# Uso dello schematic da parte di un team consumer
ng generate @azienda/ui:add-form-field --name=email-field --path=src/app/features/checkout
Storybook : configuration, modules complémentaires et histoires
Storybook est l'environnement dans lequel les composants sont développés, documentés et testés visuellement dans isolement de l'application consommateur.
# Setup iniziale in un progetto Angular esistente
npx storybook@latest init
# Addon essenziali per un design system: controls, docs automatica, a11y
npm install --save-dev @storybook/addon-a11y @storybook/addon-docs
// ds-button.stories.ts
const meta: Meta = {
title: 'Components/Button',
component: DsButtonComponent,
tags: ['autodocs'],
argTypes: {
variant: { control: 'select', options: ['primary', 'secondary', 'danger'] },
},
};
export default meta;
export const Primary: StoryObj = {
args: { variant: 'primary' },
render: (args) => ({ props: args, template: `Conferma` }),
};
L'addon a11y exécute automatiquement axe-core sur chaque étage à chaque construction, transformant
Livre d'histoires dans une porte d'accessibilité continue au lieu d'une vérification manuelle occasionnelle avant
de la sortie.
Emballage et publication sur npm
L'empaquetage d'une bibliothèque angulaire nécessite ng-packagr, qui génère une sortie compatible
avec Ivy (compilation partielle), le bundle FESM et les définitions de types sont correctes.
// ng-package.json
{
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
"dest": "../../dist/ui",
"lib": {
"entryFile": "src/public-api.ts"
}
}
// package.json della libreria — peerDependencies, non dependencies dirette
{
"name": "@azienda/ui",
"version": "3.4.0",
"peerDependencies": {
"@angular/core": "^17.0.0 || ^18.0.0",
"@angular/common": "^17.0.0 || ^18.0.0"
},
"sideEffects": false
}
# Build, verifica del pacchetto e publish
npx ng-packagr -p ng-package.json
npm pack --dry-run dist/ui
npm publish dist/ui --access public
peerDependencies au lieu de dependencies directes est le bon choix pour
Angular/RxJS : évitez que chaque application grand public ne se retrouve avec deux copies d'Angular dans le bundle final.
sideEffects : false dans package.json permet le tremblement d'arborescence côté consommateur, comme celui-ci
l'importation d'un seul composant ne fait pas glisser la bibliothèque entière dans le bundle.
Tests : unitaires, visuels, E2E
// Unit test con snapshot dell'output renderizzato
it('applica la classe corretta per variant="danger"', () => {
const fixture = TestBed.createComponent(DsButtonComponent);
fixture.componentRef.setInput('variant', 'danger');
fixture.detectChanges();
expect(fixture.nativeElement.querySelector('button').className).toContain('ds-btn--danger');
});
Le test visuel (Chromatic ou Percy intégré à Storybook) prend une capture d'écran de chaque histoire à chaque demande d'extraction et signale automatiquement toute différence de pixel par rapport à la ligne de base - c'est le seul moyen pratique de constater une régression visuelle involontaire sur un composant usagé à des dizaines de points différents de l’organisation. Les tests E2E (Cypress/Playwright) sur Le système de conception lui-même devrait être limité à des flux d'interaction complexes (un sélecteur de date, un saisie semi-automatique avec recherche asynchrone), et non à chaque composant individuel - pour la plupart les composants, les tests unitaires ainsi que les tests visuels couvrent déjà le principal risque.
CI/CD : Pipeline pour la construction, le test, le déploiement et la publication
- Build :
ng-packagrvérification de type plus complète sur chaque demande d'extraction, pas seulement sur la branche principale. - Test : test unitaire, régression visuelle et vérification a11y en tant qu'étapes distinctes et bloquantes — un échec a11y bloque la fusion tout comme un test interrompu.
- Déployer Storybook : publication automatique d'un aperçu du Storybook pour chaque pull request, afin que les réviseurs (même non techniques) puissent vérifier visuellement chaque composant modifié avant approbation.
- Publish npm : automatisé uniquement lors de la fusion dans main, avec une gestion des versions sémantiques automatiquement calculée à partir des commits (Conventional Commits + sémantique-release), jamais de publication manuelle depuis un ordinateur portable.
Jetons de thème et de conception
Les conceptions de jetons sont la source unique de vérité pour les couleurs, l'espacement, la typographie et les rayons des bordures, de qui dérivent automatiquement des propriétés personnalisées CSS, un fichier SCSS et une exportation JSON pour les outils conception (Figma).
// tokens/colors.json — fonte di verità
{
"color": {
"primary": { "value": "#2563eb" },
"danger": { "value": "#dc2626" }
}
}
/* Output generato: CSS custom properties */
:root {
--ds-color-primary: #2563eb;
--ds-color-danger: #dc2626;
}
Chaque composant consomme uniquement des propriétés CSS personnalisées, jamais de valeurs codées en dur : c'est ça qui permet à une application grand public d'appliquer un thème personnalisé (marque blanche, mode sombre) en remplaçant simplement les variables au niveau racine, sans toucher au code du composant.
Gouvernance et documentation
Un système de conception sans gouvernance explicite se dégrade rapidement en un ensemble de composants incohérent. Nous avons besoin d'une politique écrite pour les changements avec rupture (dépréciation au moins une version mineure annoncée avant la suppression, avec un avertissement d'exécution en cours de développement), un CHANGELOG généré automatiquement par les commits conventionnels, et un contribution claire qui définit qui approuve les nouveaux composants et avec quels critères (duplique un modèle existant ? Est-ce vraiment nécessaire dans le système de conception ou est-ce spécifique à une seule application ?).
Accessibilité : liste de contrôle et exemples ARIA
- Chaque élément interactif peut être parcouru et activé par le clavier (
Tab,Entrée,Espace), et pas seulement par la souris. - State
aria-disabled/aria-busycorrectement exposé pendant les états de chargement, pas seulement l'attribut natifdisabled. - Contraste de couleur minimum WCAG AA (4,5:1 pour le texte brut) vérifié dans la conception des jetons eux-mêmes, non laissé à la discrétion de ceux qui consomment le composant.
- Les composants composites (liste déroulante, modale, onglet) implémentent le modèle ARIA APG correct, y compris
role,aria-expandedet la gestion des pièges de focus si nécessaire.
<!-- Esempio: componente tab conforme ARIA APG -->
<div role="tablist" aria-label="Impostazioni account">
<button role="tab" [attr.aria-selected]="active() === 'profile'" id="tab-profile">Profilo</button>
<button role="tab" [attr.aria-selected]="active() === 'security'" id="tab-security">Sicurezza</button>
</div>
Performances et taille du paquet
- Tree-shaking : points d'entrée séparés par composant (
@company/ui/button,@company/ui/input) au lieu d'un seul fichier tonneau, donc l'importation d'un composant ne fait pas glisser l'intégralité bibliothèque. - Chargement paresseux de composants lourds (sélecteur de date avec calendrier, éditeur de texte enrichi) via
@defer, non chargés dans le paquet initial d'applications grand public. - Bundle analyseur s'exécute en CI sur la bibliothèque elle-même, avec un seuil de taille maximale par composant qui échoue à la construction s'il est dépassé.
Étude de cas 1 : Fintech avec 4 équipes produit
Une entreprise de technologie financière composée de 4 équipes de produits indépendantes a adopté un système de conception angulaire partagé sur dépôt séparé. Après 6 mois : temps moyen de développement d'un nouvel écran réduit de 34% (moins composants réinventés à partir de zéro), les bugs d'interface utilisateur signalés en production réduits de 41 % (même implémentation validée, et non 4 variantes divergentes d'un même modèle), temps d'intégration d'un nouveau développeur frontend réduit de 3 semaines à 8 jours grâce à Storybook comme documentation vivre.
Étude de cas 2 : Marketplace B2B en phase de mise à l'échelle
Un marché B2B à grande échelle qui est passé de 1 à 3 équipes front-end en un an a initialement adopté une Nx monorepo pour le système de conception, puis a migré vers un dépôt séparé lorsque la troisième équipe a rejoint. Résultat : taille du bundle d'applications réduite de 22 % après l'introduction de points d'entrée par composant, la couverture des tests des composants partagés est passée de 45 % à 89 %, et une réduction de 60 % du temps passé sur révision du code sur les implémentations d'interface utilisateur en double entre les équipes.
Liste de contrôle opérationnel 30/60/90 jours
Jours 1 à 30 : Fondation
- Référentiel de configuration, ng-packagr et les 5 premiers composants principaux (bouton, entrée, carte, badge, spinner) — KPI : créer et publier un travail à sec.
- Storybook configuré avec un module complémentaire a11y actif sur chaque histoire — KPI : 0 violation critique a11y sur les composants principaux.
- Jetons de conception définis comme source unique de vérité — KPI : 100 % des composants de base utilisent uniquement des propriétés personnalisées CSS.
Jours 31 à 60 : Adoption
- La première équipe de consommateurs a migré vers au moins 3 composants du système de conception — KPI : réduction mesurable des CSS personnalisés en double dans cette application.
- Pipeline CI/CD complet avec publication automatique lors de la fusion — KPI : 0 publication manuelle à partir d'un ordinateur portable.
- Tests visuels actifs à chaque pull request — KPI : 0 régression visuelle involontaire s'est produite.
Jours 61-90 : Échelle
- Couverture d'au moins 20 composants couvrant 80 % des modèles d'interface utilisateur les plus courants — KPI : Audit de couverture documenté.
- Gouvernance formalisée (changement en rupture de politique, processus de contribution) — KPI : document publié et partagé avec toutes les équipes.
- Au moins une deuxième équipe de consommateurs intégrée — KPI : temps d'intégration mesuré et comparé à la première équipe.
Mini-Guide 1 : Création du premier composant du système de conception
Chaque composant public part d'une API minimale et typée, et non de la reproduction de chaque variante possible dès le premier jour.
@Component({ selector: 'ds-badge', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush,
template: `` })
export class DsBadgeComponent { tone = input<'neutral' | 'success' | 'error'>('neutral'); }
Passages clés
- Définissez l'API publique (entrée/sortie) avant d'écrire le modèle.
- Appliquer les entrées OnPush et Signal de la première validation.
- Ajoutez l'histoire Storybook dans la même demande d'extraction que le composant.
FAQ : Avec combien de composants devez-vous commencer ? 5 à 8 composants de base (bouton, entrée, badge, carte, spinner) suffisent pour valider l'ensemble du pipeline avant la mise à l'échelle.
Mini-Guide 2 : Rédaction d'un schéma personnalisé
Un schéma réduit les frictions d'adoption en traduisant la documentation en une commande exécutable, au lieu de laisser chaque équipe réinterpréter les bonnes pratiques à sa manière.
ng generate @azienda/ui:add-form-field --name=email --path=src/app/checkout
Passages clés
- Identifie un modèle répété manuellement par plusieurs équipes.
- Écrivez la
Rulequi génère le code correct en une seule commande. - Documentez le schéma dans Storybook à côté du composant qu'il échafaude.
FAQ : Un schéma en vaut-il la peine pour un seul composant ? Uniquement si ce composant nécessite un passe-partout récurrent (champ de formulaire, wrapper de validation) ; pour les composants simples, cela n'est pas nécessaire.
Mini-Guide 3 : Configuration de Storybook avec l'addon a11y
npx storybook@latest init
npm install --save-dev @storybook/addon-a11y
Passages clés
- Activez l'addon a11y dans le fichier
.storybook/main.ts. - Configurez le CI pour qu'il échoue en cas de violations automatiques critiques, et pas seulement en cas d'avertissements.
- Examinez les résultats directement dans le panneau Storybook pendant le développement, pas seulement dans CI à la fin du travail.
FAQ : Le module complémentaire a11y remplace-t-il un audit manuel ? Non : Détectez les violations automatisables (contraste, attributs ARIA manquants), et non les problèmes d'utilisabilité qui nécessitent des tests avec de vrais utilisateurs.
Mini-Guide 4 : Publier la bibliothèque sur npm avec ng-packagr
npx ng-packagr -p ng-package.json
npm publish dist/ui --access public
Passages clés
- Vérifiez que
peerDependenciescouvre toutes les versions angulaires prises en charge. - Toujours exécuter
npmpublish --dry-runavant la publication proprement dite. - Automatisez la publication dans CI, jamais manuellement à partir d'un environnement local non reproductible.
FAQ : Est-il nécessaire de publier à chaque fusion ? Non : uniquement lorsque le versioning sémantique calculé à partir des commits produit effectivement une nouvelle version (correction de bug, fonctionnalité, changement avec rupture).
Mini-Guide 5 : Exporter le jeton de conception vers CSS, SCSS et JSON
{ "color": { "primary": { "value": "#2563eb" } } }
Étapes clés
- Définissez les jetons dans un format neutre (JSON) comme source unique de vérité.
- Générer automatiquement des propriétés personnalisées CSS et des variables SCSS à partir du même fichier.
- Synchronisez les jetons avec l'outil de conception (Figma) via une exportation/importation automatisée, et non une copie manuelle.
FAQ : Les concepteurs doivent-ils modifier le JSON directement ? De préférence pas : ils travaillent dans l'outil de conception et un plugin/script synchronise les valeurs dans le référentiel de jetons.
Erreurs courantes à éviter
- Modifiez la stratégie de détection des modifications par défaut en Default : propage les ralentissements sur chaque application qui consomme le système de conception.
- Utilisez
dependenciesau lieu depeerDependenciespour Angular : provoque la duplication du framework dans le bundle consommateur. - Une lime à barillet unique qui exporte tout : élimine les secousses de l'arbre et gonfle le paquet même en utilisant un seul composant.
- Aucun module complémentaire a11y dans Storybook : les violations d'accessibilité ne sont découvertes qu'en production, alors qu'elles coûtent beaucoup plus cher à corriger.
- Publier manuellement depuis un ordinateur portable : introduit une incohérence entre les environnements et rend impossible la traçabilité des versions.
- Rupture des modifications sans dépréciation préalable : interrompre silencieusement chaque application grand public lors de la prochaine mise à jour.
- Jetons de conception en double ou codés en dur dans les composants : rend la thématisation impossible à maintenir et désaligne la conception et le code au fil du temps.
- Pas de gouvernance sur les nouveaux composants : entraîne des doublons et des variations incohérentes du même modèle en quelques mois.
Questions fréquemment posées en résumé
Qu'est-ce qu'un système de conception dans Angular ? Une bibliothèque de composants thématiques réutilisables, accessibles, publiés sous forme de package npm, qui assure une cohérence visuelle et comportementale dans toutes les applications d'une organisation.
Le monorepo ou le dépôt séparé est-il préférable pour un système de conception ? Monorepo si le système de conception dessert 1 à 2 équipes avec une itération rapide ; dépôt séparé lorsqu'il y a 3 équipes de consommateurs ou plus et qu'une API publique stable et versionnée est nécessaire.
Comment publier une bibliothèque Angular sur npm ? Avec ng-packagr pour générer une sortie compilée, peerDependencies pour Angular/RxJS et npm publication automatisée dans CI après la construction et le test.
À quoi sert Storybook dans un système de conception ? Il s'agit d'un environnement isolé de développement, de documentation et de test visuel pour les composants, avec des modules complémentaires pour les contrôles interactifs et la vérification automatique de l'accessibilité.
Comment gérer le thème d'un système de conception ? Grâce à des jetons de conception exportés en tant que propriétés personnalisées CSS, consommés par des composants au lieu de valeurs codées en dur, voici comment un thème personnalisé est appliqué en remplaçant les variables au niveau racine.
Que sont les schémas angulaires ? Des générateurs de code personnalisés qui échafaudent automatiquement l'utilisation correcte d'un composant ou d'un modèle, réduisant ainsi les frictions d'adoption par rapport à la copie d'exemples de la documentation.
FAQ
Combien de composants sont nécessaires pour lancer la première version ?
5-8 composants de base couvrent la plupart des cas d'utilisation initiaux et vous permettent de valider l'ensemble du pipeline avant la mise à l'échelle.
Avez-vous besoin de Nx pour créer un système de conception angulaire ?
Non, cela est particulièrement utile dans un monorepo avec plusieurs projets, mais un système de conception dans un dépôt séparé fonctionne également bien avec la CLI angulaire seule.
Comment les modifications avec rupture sont-elles gérées ?
Avec une politique de dépréciation : avertir au moment de l'exécution au moins une version mineure avant la suppression effective, documentée dans le CHANGELOG.
Les tests visuels sont-ils obligatoires ?
Fortement recommandé sur une douzaine de composants partagés : sans cela, les régressions visuelles ne sont découvertes que par les utilisateurs finaux.
Comment mesurez-vous le succès d'un système de conception ?
Avec des KPI objectifs : réduction du temps de développement par écran, réduction des bugs UI en production, délai d'intégration des nouveaux développeurs.
Avez-vous besoin du mode strict TypeScript pour une bibliothèque publique ?
Oui, c'est fortement recommandé : une bibliothèque consommée par plusieurs équipes bénéficie plus que tout autre code d'un système de typage strict.
Comment tester des composants avec un état complexe ?
Avec des tests unitaires destinés à la logique interne et des tests visuels pour la sortie rendue, en réservant E2E uniquement aux flux d'interaction les plus complexes.
Les jetons de conception doivent-ils être versionnés avec les composants ?
Oui, dans le même référentiel et dans le même cycle de release, car un changement de token est en fait un changement de l'API visuelle.
Comment empêcher chaque équipe de créer des variations divergentes d'un même composant ?
Avec un processus de contribution clair qui vous oblige à vérifier l'existence d'un modèle similaire avant d'en créer un nouveau.
Combien de temps faut-il pour construire un système de conception mature ?
Généralement 3 à 6 mois pour une bibliothèque robuste avec plus de 20 composants, une gouvernance et un pipeline CI/CD complet, en fonction de la taille de l'équipe dédiée.
Conclusion
Un système de conception angulaire bien construit n'est pas un projet « ponctuel » : c'est un produit interne avec i ses utilisateurs (les développeurs des équipes consommateurs), sa feuille de route et sa gouvernance. Composants OnPush avec API typée, Storybook comme documentation vivante, ng-packagr pour le packaging correct et un pipeline CI/CD qui automatise les tests, la régression visuelle et la publication sont les éléments qui distinguer un système de conception véritablement adopté d'une bibliothèque de composants abandonnés après quelques mois.
Vous souhaitez une liste de contrôle imprimable ou une évaluation de votre bibliothèque de composants existante ? Demander un audit technique : en quelques heures d'analyse il est possible d'identifier les lacunes d'accessibilité, priorités de performance et de gouvernance pour votre système de conception.