Créer un bouton polymorphe avec Typescript, React, Next.js & TailwindCSS
Dans une application web, il n’est pas rare de voir un composant qui a différents comportements sans que son style change.
Par exemple, un bouton peut avoir un onClick, mais il peut également avoir un href venant d'un <a> ou d'un <Link> de Next.js.
Peu importe son comportement, le composant bouton doit conserver le style du design system : c’est là qu’interviennent les composants dits “polymorphes”.
Dans cet article, nous allons voir comment créer un bouton polymorphe, qui garde un style similaire mais peut changer son comportement.
Objectif
Le but est simple : avoir un composant bouton capable de changer d'élément html à sa racine.
Par exemple, un bouton peut avoir le comportement d’un lien ou d’un bouton, et donc avoir les attributs de son élément à la racine.
Bien que nous ayons des composants avec un style similaire, si on inspecte le DOM, les éléments à la racine du composant bouton sont bien différents.
Avantages
La création d’un composant polymorphe présente plusieurs avantages :
- Cohérence de la structure HTML : pas de button et de a imbriqués les uns dans les autres, les crawlers interprètent correctement la structure de l’application web.
- Flexibilité : en plus des éléments button et a, le composant peut prendre n’importe quel élément, par exemple une div avec un role=”button”.
- Robustesse : grâce à Typescript, selon l’élément renseigné, mon IDE interprète correctement les attributs attendus (un lien a un href mais un bouton n’en a pas)
1. Création du composant bouton
La première étape est de créer un bouton :
Ici, le composant bouton attend des attributs similaires aux attributs HTML en props. Il n’est pas dynamique et son élément à la racine est obligatoirement un button.
2. Ajouter le style du bouton
La suite logique est d’ajouter du style au bouton pour correspondre à un potentiel design system.
Nous allons utiliser CVA avec TailwindCSS et tailwind-merge. Vous pouvez consulter notre tutoriel pour intégrer un design system avec CVA.
Le composant button peut maintenant prendre un intent en props. Il ne reste plus qu’à gérer l’aspect polymorphe du bouton.
3. Modifier l’attribut as pour prendre en paramètre un élément
Maintenant, il faut pouvoir renseigner l’élément que l’on souhaite utiliser à la racine du composant.
La convention veut que nous utilisions l’attribut as={Element}. Il faut donc Omit le tag as qui existe par défaut pour certains éléments HTML et attendre un type Element.
4. Utiliser les types dynamiques
Enfin, il ne reste plus qu’à changer dynamiquement l’élément à la racine et interpréter intelligemment les types attendus selon chaque élément.
Par défaut, notre composant est un bouton, nous gardons donc cet élément si as n’est pas renseigné lors de l’instanciation du composant.
Conclusion
La création d'un bouton polymorphe avec Typescript pour React / Next.js en utilisant TailwindCSS offre une solution élégante pour maintenir la cohérence du style et la flexibilité dans le choix des éléments HTML.
Avec cette approche, la structure HTML reste propre et compréhensible par les crawlers, améliorant l'accessibilité et l'UX.
De plus, l’utilisation de Typescript permet de bénéficier des avantages que nous avons listé dans notre article Pourquoi utiliser Typescript dans un project React & Next.js ?.
Avec la combinaison d’un bouton polymorphe et d’une approche de style avec CVA, ce composant est robuste, flexible et évolutif.