Thomas Zilliox
Expert CSS Freelance à Lyon

Des classes sur l'élément racine

Angular est un framework basé sur les custom components, donc on n'a pas accès à l'élément racine depuis notre template.

Ça peut être très frustrant quand on a l'habitude des frameworks concurents, comme React ou VueJS. Pas la peine de se prendre la tête non-plus, c'est tout à fait possible de définir des attributs sur notre élément racine, par contre ça se fera depuis notre code JavaScript. J'ai noté trois solutions, je vous les présente de la plus simple à la plus compliquée.

1. Décorateur de composant

Lorsque l'on définit un nouveau composant, on utilise le décorateur @Component(). Celui-ci marque une classe comme étant "un composant angular" et nous permet de définir des méta-données de configuration.

La première solution est donc d'utiliser la méta-donnée host du décorateur de composant. Cette propriété nous permet d'ajouter des attributs et des événements directement sur l'élément racine.

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

@Component({
  selector: "my-component",
  templateUrl: "./my-component.component.html",
  styleUrls: ["./my-component.component.scss"],
  host: {
    class: "c-my-component c-my-component--full"
  }
})
export class MyComponent {}

Le code précédent définit un composant angular my-component que vous pouvez utiliser comme ceci :

<my-component></my-component>

Le DOM généré sera :

<my-component class="c-my-component c-my-component--full"></my-component>

Source : la documentation d'Angular.

2. Décorateur d'attribut

La deuxième solution permet d'avoir une gestion un peu plus fine des classes à associer à notre composant. Il n'est pas possible avec le décorateur de composant d'avoir de logique sur les classes à appliquer. Ainsi, on ne peut pas appliquer la classe c-my-component--full en fonction des attributs de notre composant angular.

Si on a ce besoin de logique, on peut alors utiliser le décorateur d'attribut @HostBinding() :

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

@Component({
  selector: "my-component",
  templateUrl: "./my-component.component.html",
  styleUrls: ["./my-component.component.scss"],
})
export class MyComponent {
  @HostBinding("class.c-my-component") readonly rootClass = true;
  @HostBinding("class.c-my-component--full") @Input() isFull: boolean = false;
}

On pourra donc utiliser l'attribut isFull pour appliquer ou pas notre classe :

<my-component></my-component> <my-component [isFull]="true"></my-component>

Le DOM généré sera :

<my-component class="c-my-component"></my-component>
<my-component class="c-my-component c-my-component--full"></my-component>

Source : la documentation d'Angular.

3. Décorateur de méthode

Si on a beaucoup de classes possibles, la méthode précédente peut être un peu verbeuse. Un autre défaut est qu'on ne peut pas créer des noms de classes dynamiques.

Pour palier à ces problèmes, il est également possible d'utiliser le décorateur @HostBinding() sur une méthode.

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

@Component({
  selector: "my-component",
  templateUrl: "./my-component.component.html",
  styleUrls: ["./my-component.component.scss"]
})
export class MyComponent {
  @Input() theme: string;

  @HostBinding("class")
  get hostClasses(): string {
    let classes = ["c-my-component"];
    if (this.theme) {
      classes.push(`c-my-component--${this.theme}`);
    }

    return classes.join(" ");
  }
}

On pourra alors utiliser l'attribut theme pour appliquer des classes dynamiques :

<my-component></my-component> <my-component [theme]="dark"></my-component>

Le DOM généré sera :

<my-component class="c-my-component"></my-component>
<my-component class="c-my-component c-my-component--dark"></my-component>

@Happy(coding), Thomas.

That's my face!

Thomas ZILLIOX

Je suis Thomas Zilliox, l'homme qui murmurait à l'oreille des chevrons, un développeur CSS freelance sur Lyon.

Je suis aussi le co-créateur de la société Zupple qui crée, organise, et anime des team building et escape games à Lyon.