Construire des composants React réutilisables à l'aide de Tailwind

Publié: 2022-03-10
Résumé rapide ↬ Tailwind est un framework CSS populaire d'abord utilitaire qui fournit des noms de classe de bas niveau aux développeurs Web. Il n'a pas de JavaScript et fonctionne bien avec les frameworks existants tels que React, Vue, Angular, Ember et autres. Bien que cela soit positif, il peut être déroutant pour les nouveaux développeurs de comprendre comment intégrer Tailwind dans leurs applications. Dans cet article, nous explorerons les moyens de créer des composants React réutilisables à l'aide de Tailwind.

Dans cet article, nous examinerons plusieurs façons différentes de créer des composants React réutilisables qui tirent parti de Tailwind sous le capot tout en exposant une belle interface à d'autres composants. Cela améliorera votre code en passant de longues listes de noms de classe à des accessoires sémantiques plus faciles à lire et à entretenir.

Vous devrez avoir travaillé avec React pour bien comprendre ce post.

Tailwind est un framework CSS très populaire qui fournit des classes utilitaires de bas niveau pour aider les développeurs à créer des conceptions personnalisées. Il a gagné en popularité au cours des dernières années car il résout très bien deux problèmes :

  1. Tailwind permet d'apporter facilement des modifications itératives au code HTML sans parcourir les feuilles de style pour trouver des sélecteurs CSS correspondants.
  2. Tailwind a des conventions et des valeurs par défaut saines. Cela permet aux gens de se lancer facilement sans avoir à écrire du CSS à partir de zéro.

Ajoutez la documentation complète et il n'est pas surprenant que Tailwind soit si populaire.

Ces méthodes vous aideront à transformer le code qui ressemble à ceci :

 <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> Enable </button>

Pour coder qui ressemble à ceci :

 <Button size="sm" textColor="white" bgColor="blue-500"> Enable </Button>

La différence entre les deux extraits est que dans le premier, nous avons utilisé une balise de bouton HTML standard, tandis que le second a utilisé un composant <Button> . Le composant <Button> a été construit pour être réutilisable et est plus facile à lire car il a une meilleure sémantique. Au lieu d'une longue liste de noms de classes, il utilise des propriétés pour définir divers attributs tels que size , textColor et bgColor .

Commençons.

Plus après saut! Continuez à lire ci-dessous ↓

Méthode 1 : contrôler les classes avec le module Classnames

Un moyen simple d'adapter Tailwind dans une application React consiste à adopter les noms de classe et à les basculer par programmation.

Le module classnames npm facilite le basculement des classes dans React. Pour montrer comment vous pouvez l'utiliser, prenons un cas d'utilisation où vous avez des composants <Button> dans votre application React.

 // This could be hard to read. <button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Enable</button> // This is more conventional React. <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>

Voyons comment séparer les classes Tailwind afin que les personnes utilisant ce composant <Button> puissent utiliser les accessoires React tels que size , textColor et bgColor .

  1. Passez des accessoires tels que bgColor et textColor directement dans le modèle de chaîne de nom de classe.
  2. Utilisez des objets pour changer par programme les noms de classe (comme nous l'avons fait avec le prop size )

Dans l'exemple de code ci-dessous, nous allons examiner les deux approches.

 // Button.jsx import classnames from 'classnames'; function Button ({size, bgColor, textColor, children}) { return ( <button className={classnames("bg-${bgColor} text-${textColor} font-bold py-2 px-4 rounded", { "text-xs": size === 'sm' "text-xl": size === 'lg', })}> {children} </button> ) }; export default Button;

Dans le code ci-dessus, nous définissons un composant Button qui prend les accessoires suivants :

  • size
    Définit la taille du bouton et applique les classes Tailwind text-xs ou text-xl
  • bgColor
    Définit la couleur d'arrière-plan du bouton et applique les classes Tailwind bg-* .
  • textColor
    Définit la couleur du texte du bouton et applique les text-* classes .
  • children
    Tous les sous-composants seront transmis ici. Il contiendra généralement le texte dans le <Button> .

En définissant Button.jsx , nous pouvons maintenant l'importer et utiliser les accessoires React au lieu des noms de classe. Cela rend notre code plus facile à lire et à réutiliser.

 import Button from './Button'; <Button size="sm" textColor="white" bgColor="blue-500">Enable</Button>

Utilisation des noms de classe pour les composants interactifs

Un bouton est un cas d'utilisation très simple. Qu'en est-il de quelque chose de plus compliqué ? Eh bien, vous pouvez aller plus loin pour créer des composants interactifs.

Par exemple, regardons une liste déroulante créée à l'aide de Tailwind.


Une liste déroulante interactive construite à l'aide de Tailwind et du basculement du nom de classe.

Pour cet exemple, nous créons le composant HTML en utilisant les noms de classe CSS Tailwind, mais nous exposons un composant React qui ressemble à ceci :

 <Dropdown options={\["Edit", "Duplicate", "Archive", "Move", "Delete"\]} onOptionSelect={(option) => { console.log("Selected Option", option)} } />

En regardant le code ci-dessus, vous remarquerez que nous n'avons pas de classes Tailwind. Ils sont tous cachés dans le code d'implémentation de <Dropdown/> . L'utilisateur de ce composant Dropdown n'a qu'à fournir une liste d' options et un gestionnaire de clic, onOptionSelect lorsqu'une option est cliquée.

Voyons comment ce composant peut être construit à l'aide de Tailwind.

En supprimant une partie du code sans rapport, voici le nœud de la logique. Vous pouvez voir ce Codepen pour un exemple complet.

 import classNames from 'classnames'; function Dropdown({ options, onOptionSelect }) { // Keep track of whether the dropdown is open or not. const [isActive, setActive] = useState(false); const buttonClasses = `inline-flex justify-center w-full rounded-md border border-gray-300 px-4 py-2 bg-white text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-blue-500 active:text-gray-200 transition ease-in-out duration-150`; return ( // Toggle the dropdown if the button is clicked <button onClick={() => setActive(!isActive)} className={buttonClasses}> Options </button> // Use the classnames module to toggle the Tailwind .block and .hidden classes <div class={classNames("origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg", { block: isActive, hidden: !isActive })}> // List items are rendered here. {options.map((option) => <div key={option} onClick={(e) => onOptionSelect(option)}>{option}</div>)} </div> ) } export default Dropdown;

La liste déroulante est rendue interactive en l'affichant ou en la masquant de manière sélective à l'aide des classes .hidden et .block . Chaque fois que le <button> est pressé, nous lançons le gestionnaire onClick qui bascule l'état isActive . Si le bouton est actif ( isActive === true ), nous définissons la classe de block . Sinon, nous définissons la classe hidden . Ce sont les deux classes Tailwind pour basculer le comportement d'affichage.

En résumé, le module classnames est un moyen simple et efficace de contrôler par programme les noms de classe pour Tailwind. Cela facilite la séparation de la logique en accessoires React, ce qui facilite la réutilisation de vos composants. Cela fonctionne pour des composants simples et interactifs.

Méthode 2 : Utiliser des constantes pour définir un système de conception

Une autre façon d'utiliser Tailwind et React ensemble consiste à utiliser des constantes et à mapper des accessoires sur une constante spécifique. Ceci est efficace pour les systèmes de conception de bâtiments. Démontrons avec un exemple.

Commencez avec un fichier theme.js lequel vous répertoriez votre système de conception.

 // theme.js (you can call it whatever you want) export const ButtonType = { primary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", secondary: "bg-blue-500 hover:bg-blue-700 text-white font-bold rounded", basic: "bg-white hover:bg-gray-700 text-gray-700 font-bold rounded", delete: "bg-red-300 hover:bg-red-500 text-white font-bold rounded" }; export const ButtonSize = { sm: "py-2 px-4 text-xs", lg: "py-3 px-6 text-lg" }

Dans ce cas, nous avons deux ensembles de constantes :

  • ButtonType définit le style des boutons dans notre application.
  • ButtonSizes définit la taille des boutons dans notre application.

Maintenant, écrivons notre composant <Button> :

 import {ButtonType, ButtonSize} from './theme'; function Button({size, type, children}) { // This can be improved. I'm keeping it simple here by joining two strings. const classNames = ButtonType[type] + " " + ButtonSize[size]; return ( <button className={classNames}>{children}</button> ) } export default Button;

Nous utilisons les constantes ButtonType et ButtonSize pour créer une liste de noms de classe. Cela rend l'interface de notre <Button> beaucoup plus agréable. Cela nous permet d'utiliser des accessoires de size et de type au lieu de tout mettre dans une chaîne de nom de classe.

 // Cleaner and well defined props. <Button size="xs" type="primary">Enable</Button>

Par rapport à l'approche précédente :

 // Exposing class names <button className="py-2 px-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Enable</button>

Si vous avez besoin de redéfinir l'apparence des boutons dans votre application, modifiez simplement le fichier theme.js et tous les boutons de votre application seront automatiquement mis à jour. Cela peut être plus facile que de rechercher des noms de classe dans divers composants.

Méthode 3 : Composer des utilitaires avec @apply

Une troisième façon d'améliorer la lisibilité de vos composants React consiste à utiliser CSS et le modèle @apply disponible dans PostCSS pour extraire les classes répétées. Ce modèle implique l'utilisation de feuilles de style et de post-processeurs.

Montrons comment cela fonctionne à travers un exemple. Supposons que vous ayez un groupe de boutons qui a un bouton principal et un bouton secondaire.

Un groupe de boutons composé d'un bouton principal et d'un bouton secondaire
Un groupe de boutons composé d'un bouton principal et d'un bouton secondaire. ( Grand aperçu )
 <button className="py-2 px-4 mr-4 text-xs bg-blue-500 hover:bg-blue-700 text-white font-bold rounded">Update Now</button> <button className="py-2 px-4 text-xs mr-4 hover:bg-gray-100 text-gray-700 border-gray-300 border font-bold rounded">Later</button>

En utilisant le modèle @apply , vous pouvez écrire ce HTML comme :

 <button className="btn btn-primary btn-xs">Update Now</button> <button className="btn btn-secondary btn-xs">Later</button>

Qui peut ensuite être adopté pour React pour devenir :

 import classnames from "classnames"; function Button ({size, type, children}) { const bSize = "btn-" + size; const bType = "btn-" + type; return ( <button className={classnames("btn", bSize, bType)}>{children}</button> ) } Button.propTypes = { size: PropTypes.oneOf(['xs, xl']), type: PropTypes.oneOf(['primary', 'secondary']) }; // Using the Button component. <Button type="primary" size="xs">Update Now</Button> <Button type="secondary" size="xs">Later</Button>

Voici comment créer ces noms de classe de style BEM tels que .btn , .btn-primary et autres. Commencez par créer un fichier button.css :

 /\* button.css \*/ @tailwind base; @tailwind components; .btn { @apply py-2 px-4 mr-4 font-bold rounded; } .btn-primary { @apply bg-blue-500 hover:bg-blue-700 text-white; } .btn-secondary { @apply hover:bg-gray-700 text-gray-700 border-gray-300 border; } .btn-xs { @apply text-xs; } .btn-xl { @apply text-xl; } @tailwind utilities;

Le code ci-dessus n'est pas un vrai CSS mais il sera compilé par PostCSS. Un référentiel GitHub est disponible ici qui montre comment configurer PostCSS et Tailwind pour un projet JavaScript.

Il y a aussi une courte vidéo qui montre comment le configurer ici.

Inconvénients de l'utilisation de @apply

Le concept d'extraction des classes utilitaires Tailwind dans des classes CSS de niveau supérieur semble avoir du sens, mais il présente certains inconvénients dont vous devez être conscient. Soulignons-les avec un autre exemple.

Tout d'abord, en extrayant ces noms de classe, nous perdons certaines informations. Par exemple, nous devons être conscients que .btn-primary doit être ajouté à un composant auquel .btn est déjà appliqué. De plus, .btn-primary et .btn-secondary ne peuvent pas être appliqués ensemble. Cette information n'est pas évidente en regardant simplement les classes.

Si ce composant était quelque chose de plus compliqué, vous auriez également besoin de comprendre la relation parent-enfant entre les classes. D'une certaine manière, c'est le problème que Tailwind a été conçu pour résoudre, et en utilisant @apply , nous ramenons les problèmes, d'une manière différente.

Voici une vidéo dans laquelle Adam Wathan, le créateur de Tailwind, se penche sur les avantages et les inconvénients de l'utilisation de @apply .

Sommaire

Dans cet article, nous avons examiné trois façons d'intégrer Tailwind dans une application React pour créer des composants réutilisables. Ces méthodes vous aident à créer des composants React dotés d'une interface plus propre à l'aide de props .

  1. Utilisez le module classnames pour basculer les classes par programmation.
  2. Définissez un fichier de constantes dans lequel vous définissez une liste de classes par état de composant.
  3. Utilisez @apply pour extraire les classes CSS de niveau supérieur.

Si vous avez des questions, envoyez-moi un message sur Twitter à @tilomitra.

Lecture recommandée sur SmashingMag :

  • Configuration de Tailwind CSS dans un projet React
  • Créer des tableaux triables avec React
  • Un guide des outils de développement CSS nouveaux et expérimentaux dans Firefox
  • Créez vos propres panneaux de contenu extensibles et rétractables