Angular Material Theming : design system cohérent

🏷️ Front-end 📅 14/04/2026 01:10:00 👤 Mezgani said
Angular Angular Material Theming Design System Ui
Angular Material Theming : design system cohérent

Créez un design system Angular Material maintenable : palettes, tokens, thèmes clair/sombre et personnalisation scalable.

Installation Angular Material

Angular Material est la librairie UI officielle d'Angular. Depuis Angular 17, elle supporte nativement le Material Design 3 (M3) avec un système de tokens CSS.

ng add @angular/material

Le CLI te demande :

  • Un thème préconçu (Indigo/Pink, Azure/Blue…) ou un thème personnalisé.
  • Si tu souhaites activer la typographie globale Material.
  • Si tu actives les animations (BrowserAnimationsModule).
Recommandation: Choisis "custom theme" dès le départ pour garder le contrôle total sur tes couleurs et tokens — même si tu pars d'une palette proche d'un thème existant.

Le fichier généré src/styles.scss inclut automatiquement l'import Material et l'application du thème.

Tokens et palettes personnalisées

Avec M3, Angular Material utilise des tokens CSS (variables) pour toutes les couleurs, typographies et espacements. Tu définis une palette via define-theme().

// styles.scss
@use '@angular/material' as mat;

// Définir la palette couleur
$mon-theme: mat.define-theme((
    color: (
        theme-type: light,
        primary: mat.$azure-palette,
        tertiary: mat.$blue-palette
    ),
    typography: (
        brand-family: 'Manrope, sans-serif',
        bold-weight: 700
    ),
    density: (
        scale: 0
    )
));

html {
    @include mat.all-component-themes($mon-theme);
}

Palettes disponibles

  1. Palettes M3 prédéfinies : $red-palette, $green-palette, $azure-palette, $violet-palette
  2. Pour une palette totalement custom, utilise mat.define-palette() avec tes propres valeurs HEX.

Thèmes clair et sombre

M3 rend le mode sombre trivial : il suffit de définir deux variantes du thème et de basculer sur prefers-color-scheme ou un attribut HTML.

// styles.scss
@use '@angular/material' as mat;

$theme-clair: mat.define-theme((
    color: (theme-type: light, primary: mat.$azure-palette)
));

$theme-sombre: mat.define-theme((
    color: (theme-type: dark, primary: mat.$azure-palette)
));

// Appliquer le thème clair par défaut
html {
    @include mat.all-component-themes($theme-clair);
}

// Basculer en sombre via attribut data-theme="dark" ou media query
html[data-theme="dark"] {
    @include mat.all-component-color-themes($theme-sombre);
}

@media (prefers-color-scheme: dark) {
    html:not([data-theme="light"]) {
        @include mat.all-component-color-themes($theme-sombre);
    }
}

Pour basculer dynamiquement depuis Angular :

@Injectable({ providedIn: 'root' })
export class ThemeService {
    private readonly darkMode = signal(false);

    toggleTheme(): void {
        this.darkMode.update(v => !v);
        document.documentElement.setAttribute(
            'data-theme',
            this.darkMode() ? 'dark' : 'light'
        );
    }
}

Composants wrapper métier

Plutôt que d'utiliser directement mat-button partout, crée des composants wrapper qui encapsulent tes conventions (variante, taille, icone) et exposent une API simplifiée.

// af-button.component.ts
import { Component, Input } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';

@Component({
    selector: 'af-button',
    standalone: true,
    imports: [MatButtonModule, MatIconModule],
    template: `
        <button
            mat-flat-button
            [color]="color"
            [disabled]="disabled"
            [attr.aria-label]="label"
        >
            @if (icon) { <mat-icon>{{ icon }}</mat-icon> }
            {{ label }}
        </button>
    `
})
export class AfButtonComponent {
    @Input() label = '';
    @Input() icon = '';
    @Input() color: 'primary' | 'accent' | 'warn' = 'primary';
    @Input() disabled = false;
}
Avantage: Si Material change son API interne (M2 → M3), tu n'as qu'un seul fichier à mettre à jour au lieu de dizaines de composants.

Typographie et spacing

Angular Material expose des classes utilitaires pour la typographie M3. Applique-les directement sur tes éléments HTML sans créer de styles custom.

<!-- Niveaux typographiques M3 -->
<h1 class="mat-display-large">Titre principal</h1>
<h2 class="mat-headline-medium">Sous-titre</h2>
<p class="mat-body-large">Corps de texte standard</p>
<span class="mat-label-small">Libellé discret</span>

Pour le spacing, utilise la fonction SCSS mat.private-token() ou définit tes propres variables en cohérence avec la density scale :

// Density scale : 0 (défaut), -1, -2, -3
// -1 réduit légèrement les composants (boutons, inputs)
// Utile pour les tableaux denses ou dashboards
$theme-dense: mat.define-theme((
    color: (theme-type: light, primary: mat.$azure-palette),
    density: (scale: -2)
));

Accessibilité et contrastes

Angular Material respecte les critères WCAG 2.1 AA par défaut sur ses composants. Cependant, si tu personnalises les couleurs, tu dois valider les contrastes toi-même.

  • Vérifier le ratio de contraste texte/fond avec l'outil WebAIM Contrast Checker — minimum 4.5:1 pour le texte normal.
  • Tester la navigation au clavier sur chaque composant interactif (bouton, input, dialog, menu).
  • Ne pas supprimer le focus ring de Material — il est essentiel pour les utilisateurs clavier.
  • Ajouter aria-label sur les icônes sans texte visible (<mat-icon aria-label="Fermer">).
  • Utiliser mat-error et mat-hint dans les formulaires — ils sont lus automatiquement par les lecteurs d'écran.
  • Tester avec un mode de contraste élevé (Windows High Contrast Mode) — Material 3 le supporte nativement.