ng-content Angular : projection de contenu

🏷️ Front-end 📅 12/04/2026 00:00:00 👤 Mezgani Said
Angular Composants Ng-Content Projection Reusabilité
ng-content Angular : projection de contenu

Maîtriser ng-content pour créer des composants flexibles avec projection de contenu, slots nommés et transclusion avancée.

Qu'est-ce que ng-content ?

ng-content est un mécanisme Angular de projection de contenu (aussi appelée transclusion). Il permet à un composant parent de passer du contenu au composant enfant sans passer par les @Input classiques.

Cas d'usage clé: créer des composants réutilisables qui s'adaptent à n'importe quel contenu (cards, modales, layouts flexibles).

Avantages:

  • Composants décorés plus flexibles et composables.
  • Séparation entre la structure (composant parent) et le contenu (enfant).
  • Pas besoin de parser des strings ou manipuler le DOM manuellement.
  • Support natif de toutes les directives Angular du parent.

Projection simple de contenu

La forme la plus basique: le composant enfant place <ng-content> là où doit s'afficher le contenu du parent.

Composant Card (enfant):

import { Component } from '@angular/core';

@Component({
  selector: 'app-card',
  template: `
    <div class="card">
      <div class="card-header">
        <h3>Titre</h3>
      </div>
      <div class="card-body">
        <ng-content></ng-content>
      </div>
    </div>
  `,
  styleUrls: ['./card.component.css']
})
export class CardComponent {}

Utilisation (parent):

<app-card>
  <p>Ceci est mon contenu personnalisé</p>
  <button>Cliquez-moi</button>
</app-card>

Le paragraphe et le bouton s'affichent dans le <ng-content> du composant Card.

Slots nommés avec select

Pour projeter du contenu à plusieurs endroits, utilise l'attribut select. C'est puissant pour les layouts complexes.

Composant Modal (enfant):

@Component({
  selector: 'app-modal',
  template: `
    <div class="modal-overlay">
      <div class="modal-box">
        <div class="modal-header">
          <ng-content select=".modal-title"></ng-content>
        </div>
        <div class="modal-body">
          <ng-content></ng-content>
        </div>
        <div class="modal-footer">
          <ng-content select="[modal-action]"></ng-content>
        </div>
      </div>
    </div>
  `
})
export class ModalComponent {}

Utilisation:

<app-modal>
  <h2 class="modal-title">Confirmation</h2>

  <p>Êtes-vous sûr ?</p>

  <button modal-action (click)="onConfirm()">OK</button>
  <button modal-action (click)="onCancel()">Annuler</button>
</app-modal>

Sélecteurs disponibles

  1. select=".class-name" — sélectionne par classe CSS.
  2. select="tag-name" — sélectionne par nom de balise.
  3. select="[attribute-name]" — sélectionne par attribut.
  4. Pas de select — capture tout le contenu non-sélectionné.

Contenu par défaut et fallback

Si le parent n'envoie pas de contenu pour un slot, tu peux afficher un contenu par défaut.

@Component({
  selector: 'app-panel',
  template: `
    <div class="panel">
      <ng-content select=".panel-icon">
        <span class="default-icon">ℹ️</span>
      </ng-content>

      <div class="panel-content">
        <ng-content>
          <p>Pas de contenu fourni</p>
        </ng-content>
      </div>
    </div>
  `
})
export class PanelComponent {}
Bonus: le contenu par défaut s'affiche seulement si le parent n'envoie rien pour ce slot. C'est un bon moyen de prévoir une UX complète.

Patterns avancés

1. Accéder aux éléments projetés avec @ContentChild

import { Component, ContentChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-form-group',
  template: `<div class="form-group"><ng-content></ng-content></div>`
})
export class FormGroupComponent {
  @ContentChild('input') inputRef?: ElementRef;

  ngAfterContentInit() {
    if (this.inputRef?.nativeElement) {
      this.inputRef.nativeElement.classList.add('form-control');
    }
  }
}

2. ng-content avec *ngIf

@Component({
  template: `
    <div class="alert">
      <ng-content select=".alert-icon" *ngIf="hasIcon"></ng-content>
      <ng-content></ng-content>
    </div>
  `
})
export class AlertComponent {
  @Input() hasIcon = true;
}

Cas d'usage pratiques

  • Cards flexibles — titre, contenu, footer personnalisés.
  • Modales — header, body, footer avec projections séparées.
  • Layouts complexes — sidebar + main + footer = ng-content multiples.
  • Composed components — wrappers de formulaires, tables custom, etc.
  • Rendering conditional — afficher/cacher du contenu selon des conditions.

Bonnes pratiques et performances

  • Garder ng-content simple → utilise select plutôt que des logiques complexes.
  • Ne pas mettre trop de ng-content dans un composant (max 3-4 slots).
  • Utiliser des commentaires HTML pour documenter les slots disponibles.
  • ng-content n'a pas d'impact performance → les éléments projetés ne sont pas re-rendus inutilement.
  • Préférer les slots nommés pour l'évolutivité plutôt qu'un ng-content générique.
A retenir: ng-content = composants réutilisables = code plus maintenable et scalable.