Creación de componentes React reutilizables con Tailwind

Publicado: 2022-03-10
Resumen rápido ↬ Tailwind es un marco de trabajo CSS de primera utilidad popular que proporciona nombres de clase de bajo nivel a los desarrolladores web. No tiene JavaScript y funciona bien con marcos existentes como React, Vue, Angular, Ember y otros. Si bien esto es positivo, puede resultar confuso para los nuevos desarrolladores comprender cómo integrar Tailwind en sus aplicaciones. En este artículo, exploraremos formas de construir componentes React reutilizables usando Tailwind.

En esta publicación, veremos varias formas diferentes en las que puede crear componentes React reutilizables que aprovechan Tailwind bajo el capó mientras exponen una interfaz agradable a otros componentes. Esto mejorará su código al pasar de largas listas de nombres de clase a accesorios semánticos que son más fáciles de leer y mantener.

Deberá haber trabajado con React para comprender bien esta publicación.

Tailwind es un marco CSS muy popular que proporciona clases de utilidad de bajo nivel para ayudar a los desarrolladores a crear diseños personalizados. Ha ganado popularidad en los últimos años porque resuelve muy bien dos problemas:

  1. Tailwind facilita la realización de cambios iterativos en HTML sin tener que buscar en hojas de estilo para encontrar selectores de CSS coincidentes.
  2. Tailwind tiene convenciones y valores predeterminados sensatos. Esto facilita que las personas comiencen sin escribir CSS desde cero.

Agregue la documentación completa y no sorprende por qué Tailwind es tan popular.

Estos métodos lo ayudarán a transformar el código que se ve así:

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

Para codificar que se ve así:

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

La diferencia entre ambos fragmentos es que en el primero usamos una etiqueta de botón HTML estándar, mientras que en el segundo usamos un componente <Button> . El componente <Button> se ha creado para la reutilización y es más fácil de leer ya que tiene una mejor semántica. En lugar de una larga lista de nombres de clases, utiliza propiedades para establecer varios atributos, como size , textColor y bgColor .

Empecemos.

¡Más después del salto! Continúe leyendo a continuación ↓

Método 1: control de clases con el módulo Classnames

Una forma sencilla de adaptar Tailwind a una aplicación React es adoptar los nombres de las clases y alternarlos mediante programación.

El módulo classnames npm facilita el cambio de clases en React. Para demostrar cómo puede usar esto, tomemos un caso de uso en el que tiene componentes <Button> en su aplicación 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>

Veamos cómo separar las clases de Tailwind para que las personas que usan este componente <Button> puedan usar accesorios de React como size , textColor y bgColor .

  1. Pase accesorios como bgColor y textColor directamente a la plantilla de cadena de nombre de clase.
  2. Use objetos para cambiar los nombres de las clases mediante programación (como hemos hecho con el accesorio de size )

En el código de ejemplo a continuación, veremos ambos enfoques.

 // 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;

En el código anterior, definimos un componente Button que toma los siguientes accesorios:

  • size
    Define el tamaño del botón y aplica las clases Tailwind text-xs o text-xl
  • bgColor
    Define el color de fondo del botón y aplica las clases Tailwind bg-* .
  • textColor
    Define el color del texto del botón y aplica las text-* classes .
  • children
    Cualquier subcomponente pasará por aquí. Por lo general, contendrá el texto dentro del <Button> .

Al definir Button.jsx , ahora podemos importarlo y usar accesorios React en lugar de nombres de clase. Esto hace que nuestro código sea más fácil de leer y reutilizar.

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

Uso de nombres de clase para componentes interactivos

Un botón es un caso de uso muy simple. ¿Qué tal algo más complicado? Bueno, puede llevar esto más lejos para crear componentes interactivos.

Por ejemplo, veamos un menú desplegable que se crea con Tailwind.


Un menú desplegable interactivo creado con Tailwind y cambio de nombre de clase.

Para este ejemplo, creamos el componente HTML utilizando los nombres de clase CSS de Tailwind, pero exponemos un componente React que se ve así:

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

Mirando el código anterior, notará que no tenemos ninguna clase de Tailwind. Todos están ocultos dentro del código de implementación de <Dropdown/> . El usuario de este componente Dropdown solo tiene que proporcionar una lista de options y un controlador de clics, onOptionSelect cuando se hace clic en una option .

Veamos cómo se puede construir este componente usando Tailwind.

Eliminando parte del código no relacionado, aquí está el quid de la lógica. Puede ver este Codepen para ver un ejemplo completo.

 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;

El menú desplegable se vuelve interactivo mostrándolo u ocultándolo selectivamente usando las clases .hidden y .block . Cada vez que se presiona <button> , activamos el controlador onClick que cambia el estado isActive . Si el botón está activo ( isActive === true ), establecemos la clase de block . De lo contrario, establecemos la clase hidden . Ambas son clases de Tailwind para alternar el comportamiento de visualización.

En resumen, el módulo de nombres de clase es una forma simple y efectiva de controlar mediante programación los nombres de clase para Tailwind. Hace que sea más fácil separar la lógica en accesorios React, lo que hace que sus componentes sean más fáciles de reutilizar. Funciona para componentes simples e interactivos.

Método 2: uso de constantes para definir un sistema de diseño

Otra forma de usar Tailwind y React juntos es usar constantes y asignar accesorios a una constante específica. Esto es efectivo para sistemas de diseño de edificios. Vamos a demostrar con un ejemplo.

Comience con un archivo theme.js donde enumere su sistema de diseño.

 // 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" }

En este caso, tenemos dos conjuntos de constantes:

  • ButtonType define cómo se diseñan los botones en nuestra aplicación.
  • ButtonSizes define los tamaños de los botones en nuestra aplicación.

Ahora, escribamos nuestro componente <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;

Usamos las constantes ButtonType y ButtonSize para crear una lista de nombres de clase. Esto hace que la interfaz de nuestro <Button> sea mucho más agradable. Nos permite usar accesorios de size y type en lugar de poner todo en una cadena de nombre de clase.

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

Frente al enfoque anterior:

 // 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 necesita redefinir cómo se ven los botones en su aplicación, simplemente edite el archivo theme.js y todos los botones de su aplicación se actualizarán automáticamente. Esto puede ser más fácil que buscar nombres de clase en varios componentes.

Método 3: Componer utilidades con @apply

Una tercera forma de mejorar la legibilidad de sus componentes React es usar CSS y el patrón @apply disponible en PostCSS para extraer clases repetidas. Este patrón implica el uso de hojas de estilo y postprocesadores.

Demostremos cómo funciona esto a través de un ejemplo. Suponga que tiene un grupo de botones que tiene un botón principal y uno secundario.

Un grupo de botones que consiste en un botón primario y secundario
Un grupo de botones que consta de un botón principal y uno secundario. (Vista previa grande)
 <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>

Usando el patrón @apply , puede escribir este HTML como:

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

Que luego se puede adoptar para Reaccionar para convertirse en:

 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>

Así es como crearía estos nombres de clase de estilo BEM, como .btn , .btn-primary y otros. Comience creando un archivo 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;

El código anterior no es CSS real , pero PostCSS lo compilará. Hay un repositorio de GitHub disponible aquí que muestra cómo configurar PostCSS y Tailwind para un proyecto de JavaScript.

También hay un breve video que muestra cómo configurarlo aquí.

Desventajas de usar @apply

El concepto de extraer clases de utilidad Tailwind en clases CSS de nivel superior parece tener sentido, pero tiene algunas desventajas que debe tener en cuenta. Vamos a resaltar estos con otro ejemplo.

Primero, al extraer estos nombres de clase, perdemos algo de información. Por ejemplo, debemos tener en cuenta que .btn-primary debe agregarse a un componente que ya tiene .btn aplicado. Además, .btn-primary y .btn-secondary no se pueden aplicar juntos. Esta información no es evidente con solo mirar las clases.

Si este componente fuera algo más complicado, también necesitaría comprender la relación padre-hijo entre las clases. En cierto modo, este es el problema que se diseñó para resolver Tailwind, y al usar @apply , estamos recuperando los problemas, de una manera diferente.

Aquí hay un video donde Adam Wathan, el creador de Tailwind, se sumerge en los pros y los contras de usar @apply .

Resumen

En este artículo, analizamos tres formas en que puede integrar Tailwind en una aplicación React para crear componentes reutilizables. Estos métodos lo ayudan a crear componentes de React que tienen una interfaz más limpia usando props .

  1. Use el módulo de nombres de clase para alternar clases mediante programación.
  2. Defina un archivo de constantes donde defina una lista de clases por estado de componente.
  3. Use @apply para extraer clases CSS de nivel superior.

Si tiene alguna pregunta, envíeme un mensaje en Twitter a @tilomitra.

Lectura recomendada en SmashingMag:

  • Configuración de Tailwind CSS en un proyecto React
  • Creación de tablas ordenables con React
  • Una guía para herramientas de desarrollo de CSS nuevas y experimentales en Firefox
  • Cree sus propios paneles de contenido expandibles y contraídos