Ingénieur IT, photographe amateur, musicien du dimanche
Custom Element API
Custom Element API

Custom Element API

TL;DR;

Dans le dernier article, je vous présentais les composants web. Une des API permettant de créer des composants est l’API html5 Custom Element. Elle permet de déclarer un nouveau composant dans le DOM et que celui soit reconnu par le browser pour l’affichage et avec ses comportements spécifiques.

Depuis cet article, la spec à changé et ne colle plus à la description ci-dessous. Référez-vous plutôt à la spec V1 décrite ici :  https://developers.google.com/web/fundamentals/web-components/ 

Introduction

La notion d’élément personnalisé (Custom Element) est le fait de pouvoir créer nos propres balises, sans qu’elles soient ignorées par le navigateur. Pour cela, nous utilisons le JavaScript afin de déclarer notre composant.

Restriction

La seule restriction est que le nom de notre élément perso doit contenir un tiret   . Ceci permettra de ne pas écraser des éléments natifs à la manière de namespace.

Exemple valide : <my-element>

Exemple invalide : <element>

Création d’un élément personnalisé

La Class ou le prototype

La création de notre composant passe tout d’abord par la création d’un prototype JavaScript représentant le composant et héritant soit du prototype d’une balise HTML, soit du protoype d’un autre composant existant à étendre.

Pour la balise HTML ce sera donc HTMLElement , et pour un composant spécifique cela dépendra du composant, comme par exemple pour un input on étendra HTMLInputElement .

En ES6, ce prototype sera définit à l’aide d’une class  et de l’héritage à l’aide du mot clé extends .
Ex: class MyElement extends HTMLElement

Les propriétés et méthodes de prototype

Le contenu du prototype correspondra à toutes les propriétés et méthodes qui lui seront utiles. Mais également 4 méthodes qui concernent les différents événements qui interviendront dans son cycle de vie et que voici :

  • createdCallback()  : Méthode exécutée lorsque le composant a été créé et sa définition enregistrée
  • attachedCallback()  : Méthode exécutée lorsque l’élément a été inséré dans le DOM
  • detachedCallback()  : Méthode exécutée lorsque l’élément est retiré du DOM
  • attributeChangedCallback(attrName, oldValue, newValue)  :Méthode exécutée lorsqu’un attribut de l’élément a été modifié.

L’enregistrement de l’élément

Une fois la class créée, il ne reste plus qu’à l’enregistrer dans l’annuaire des éléments DOM reconnu par le navigateur afin qu’elle soit utilisable. Pour cela,  on utilisera la méthode document.registerElement(elementName, prototype, options) .

Cette méthode reçoit les paramètres suivants:

  1. elementName (string) est une chaine de caractère qui correspond au nom de la balise qui sera utilisée pour notre composant. Ex: on passera ‘my-button’ , si notre composant sera créé avec la balise <my-button> .
  2. prototype (object) est la class prototype définie.
  3. options (object) est un objet supplémentaire qui contiendra par exemple l’attribut prototype de l’élément étendu si on veut étendre un élément existant comme par exemple un input.
    Ex: { prototype: HTMLInputElement }

Le styling

Tant que le custom element ne contient pas de Shadow DOM, ses différentes parties peuvent être stylisée comme on le fait habituellement. Pour le style du Shadow DOM, il faudra utiliser des sélecteurs spécifiques qui sont expliqués dans l’article du même nom.

Il y’a quand même un nouveau sélecteur qui permet de cibler un état non reconnu d’un custom élément, le sélecteur :unresolved . Celui-ci nous permet d’afficher un style temporaire tant que la balise n’est pas transformée en composant. Voici un exemple d’utilisation :

my-element:unresolved {
    opacity: 0;
}
my-element:unresolved::before {
   content: 'Loading component';
}

Exemple complet

Voici un exemple de tout le processus de déclaration de custom components :

Support navigateur

Le support actuel de cette API se trouve ici :  http://caniuse.com/#feat=custom-elements

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *