Configuración, Content (Contenido)

La configuración del content

La sección content del archivo tailwind.config.js es en donde se configuran las rutas de todos los templates HTML, JS, componentes, y otros archivos fuente que contienen clases de Tailwind.

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    // ...
}

Configuración de rutas de origen

Tailwind CSS funciona escaneando tus archivos HTML, componentes de JavaScript y otros archivos de plantilla en busca de nombres de clases, y luego genera todo el CSS correspondiente para esos estilos.

Para que Tailwind pueda generar todo el CSS que necesitas, debe conocer cada archivo en tu proyecto que contenga nombres de clases de Tailwind.

Configura las rutas de todos tus archivos de contenido en la sección de contenido de tu archivo de configuración.

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    // ...
}

Las rutas se configuran como patrones globales, lo que facilita la coincidencia con todos los archivos de contenido en tu proyecto sin necesidad de mucha configuración:

  • Usa * para coincidir con cualquier cosa excepto barras inclinadas y archivos ocultos.
  • Usa ** para coincidir con cero o más directorios.
  • Usa valores separados por comas entre {} para coincidir con una lista de opciones.

Tailwind utiliza la biblioteca fast-glob en su interior; consulta su documentación para ver otras características de patrones admitidas.

Las rutas son relativas a la raíz de tu proyecto, no al archivo tailwind.config.js, por lo que si tu archivo tailwind.config.js está en una ubicación personalizada, aún debes escribir tus rutas en relación con la raíz de tu proyecto.

Recomendaciones de patrones

Para obtener el mejor rendimiento y evitar falsos positivos, sé lo más específico posible con la configuración de tu contenido.

Si usas un patrón muy amplio como este, Tailwind incluso escaneará node_modules en busca de contenido, lo cual probablemente no es lo que deseas.

Si tienes archivos que necesitas escanear que están en la raíz de tu proyecto (a menudo un archivo index.html), enuméralo de forma independiente para que tus otros patrones puedan ser más específicos:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        './components/**/*.{html,js}',
        './pages/**/*.{html,js}',
        './index.html',
    ],
    // ...
}

Algunos frameworks ocultan su punto de entrada principal HTML en un lugar diferente al resto de tus plantillas (a menudo en public/index.html). Por lo tanto, si estás agregando clases de Tailwind a ese archivo, asegúrate de incluirlo también en tu configuración.

// tailwind.config.js
module.exports = {
    content: ['./public/index.html', './src/**/*.{html,js}'],
    // ...
}

Si tienes algún archivo JS que manipule el HTML agregando clases, asegúrate de incluirlo también.

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        // ...
        './src/**/*.js',
    ],
    // ...
}
menuButton.addEventListener('click', function () {
    let classList = document.getElementById('nav').classList
    classList.toggle('oculto')
    classList.toggle('visible')
})

Es importante que no escanees archivos CSS. Configura Tailwind para analizar tus plantillas donde se utilizan los nombres de las clases, nunca el archivo CSS que genera Tailwind.

Detección profunda de clases

La forma en que Tailwind escanea tu código fuente en busca de clases es intencionalmente muy simple; no analizamos ni ejecutamos tu código en el lenguaje en el que está escrito, simplemente utilizamos expresiones regulares para extraer cada cadena que posiblemente pueda ser un nombre de clase.

<div class="md:flex">
    <div class="md:flex-shrink-0">
        <img
            class="rounded-lg md:w-56"
            src="/img/compras.jpg"
            alt="Mujer pagando una compra"
        />
    </div>
    <div class="mt-4 md:mt-0 md:ml-6">
        <div class="uppercase tracking-wide text-sm text-indigo-600 font-bold">
            Marketing
        </div>
        <a
            href="/empezar"
            class="block mt-1 text-lg leading-tight font-semibold text-gray-900 hover:underline"
        >
            Encontrar clientes para tu nuevo negocio
        </a>
        <p class="mt-2 text-gray-600">
            Poner en marcha un nuevo negocio es un trabajo arduo. Aquí tienes
            cinco ideas que puedes usar para encontrar tus primeros clientes.
        </p>
    </div>
</div>

No limitamos nuestra búsqueda solo a atributos class="..." porque podrías estar usando clases en cualquier parte, como en algún código JavaScript para alternar un menú:

<script>
    menuButton.addEventListener('click', function () {
        let classList = document.getElementById('nav').classList
        classList.toggle('oculto')
        classList.toggle('visible')
    })
</script>

Al usar este enfoque tan simple, Tailwind funciona de manera extremadamente confiable con cualquier lenguaje como JSX.

const sizes = {
    md: 'px-4 py-2 rounded-md text-base',
    lg: 'px-5 py-3 rounded-lg text-lg',
}

const colors = {
    indigo: 'bg-indigo-500 hover:bg-indigo-600 text-white',
    cyan: 'bg-cyan-600 hover:bg-cyan-700 text-white',
}

export default function Button({ color, size, children }) {
    let colorClasses = colors[color]
    let sizeClasses = sizes[size]

    return (
        <button
            type="button"
            className={`font-bold ${sizeClasses} ${colorClasses}`}
        >
            {' '}
            {children}{' '}
        </button>
    )
}

Nombres de clases dinámicas

La cosa más importante que debes entender sobre cómo Tailwind busca los nombres de las clases es que solo los encuentra si están escritos de principio a fin en tus archivos de código.

Si cortas un nombre de clase en pedazos o lo mezclas con otros textos, Tailwind no podrá encontrarlo y, por lo tanto, no creará el estilo correspondiente.

No hagas esto:

<div class="text-{{ error ? 'red' : 'green' }}-600"></div>

En su lugar has esto:

<div class="{{ error ? 'text-red-600' : 'text-green-600' }}"></div>

Si estás utilizando una biblioteca de componentes como React o Vue, esto significa que no debes usar props para construir dinámicamente clases:

function Button({ color, children }) {
    return (
        <button className={`bg-${color}-600 hover:bg-${color}-500 ...`}>
            {children}
        </button>
    )
}

En su lugar, asigna props a nombres de clases completos que sean detectables estáticamente en tiempo de compilación:

function Button({ color, children }) {
    const colores = {
        blue: 'bg-blue-600 hover:bg-blue-500',
        red: 'bg-red-600 hover:bg-red-500',
    }

    return <button className={`${colores[color]} ...`}>{children}</button>
}

Esto tiene el beneficio adicional de permitirte asignar diferentes valores de propiedades a diferentes tonos de color, por ejemplo:

function Button({ color, children }) {
    const colores = {
        blue: 'bg-blue-600 hover:bg-blue-500 text-white',
        red: 'bg-red-500 hover:bg-red-400 text-white',
        yellow: 'bg-yellow-300 hover:bg-yellow-400 text-black',
    }

    return <button className={`${colores[color]} ...`}>{children}</button>
}

Siempre y cuando uses nombres de clases completos en tu código, Tailwind generará todo tu CSS de manera perfecta en cada ocasión.

Trabajar con bibliotecas de terceros

Si estás usando bibliotecas de otras personas (como Select2) y quieres darles estilo con tu propio CSS personalizado, te recomendamos escribir esos estilos sin usar la función @layer de Tailwind:

/* main.css */
@tailwind base;
@tailwind components;

.select2-dropdown {
    @apply rounded-b-lg shadow-md;
}

.select2-search {
    @apply border border-gray-300 rounded;
}

.select2-results__group {
    @apply text-lg font-bold text-gray-900;
}

/* ... */

@tailwind utilities;

Hacerlo asegura que Tailwind siempre agregue esos estilos a tu CSS, y es más fácil que configurar Tailwind para buscar el código de una biblioteca externa.

Si hiciste tus propios componentes reutilizables con Tailwind y los usas en varios proyectos, asegúrate de decirle a Tailwind que busque las clases dentro de esos componentes.

// tailwind.config.js
module.exports = {
    content: [
        './components/**/*.{html,js}',
        './pages/**/*.{html,js}',
        './node_modules/@my-company/tailwind-components/**/*.js',
    ],
    // ...
}

Esto asegurará que Tailwind genere todo el CSS necesario para esos componentes también.

Si estás trabajando en un monorepo con workspaces, es posible que necesites usar require.resolve para asegurarte de que Tailwind pueda acceder a tus archivos de contenido:

// tailwind.config.js
const path = require('path')

module.exports = {
    content: [
        './components/**/*.{html,js}',
        './pages/**/*.{html,js}',
        path.join(
            path.dirname(require.resolve('@my-company/tailwind-components')),
            '**/*.js'
        ),
    ],
    // ...
}

Uso de rutas relativas

De forma predeterminada, Tailwind resuelve las rutas de contenido que no son absolutas en relación al directorio de trabajo actual, no al archivo tailwind.config.js. Esto puede llevar a resultados inesperados si ejecutas Tailwind desde un directorio diferente.

Para que las rutas se resuelvan siempre en relación al archivo tailwind.config.js, utiliza la notación de objeto en tu configuración de contenido y establece la propiedad relative en true:

// tailwind.config.js
module.exports = {
    content: {
        relative: true,
        files: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    },
    // ...
}

Esta probablemente se convertirá en el comportamiento predeterminado en la próxima versión del framework.

Configuración de contenido en bruto

Si por alguna razón necesitas configurar Tailwind para escanear algún contenido en bruto en lugar del contenido de un archivo, utiliza un objeto con una clave raw en lugar de una ruta:

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        './pages/**/*.{html,js}',
        './components/**/*.{html,js}',
        {
            raw: '<div class="font-bold">',
            extension: 'html',
        },
    ],
    // ...
}

Clases permitidas de forma segura

Para obtener el tamaño de archivo más pequeño y la mejor experiencia de desarrollo, recomendamos encarecidamente depender en la medida de lo posible de la configuración de tu contenido para indicar a Tailwind qué clases generar.

La lista de clases permitidas es una medida de último recurso y solo debe usarse en situaciones en las que sea imposible escanear cierto contenido en busca de nombres de clases. Estas situaciones son raras y casi nunca deberías necesitar esta función.

Si necesitas asegurarte de que Tailwind genere ciertos nombres de clases que no existen en tus archivos de contenido, utiliza la opción de lista de clases permitidas (safelist).

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    safelist: ['bg-red-500', 'text-3xl', 'lg:text-4xl'],
    // ...
}

Un ejemplo en el que esto puede ser útil es si tu sitio muestra contenido generado por los usuarios y quieres que los usuarios puedan utilizar un conjunto limitado de clases de Tailwind en su contenido que quizás no existan en los archivos fuente de tu propio sitio.

Uso de expresiones regulares

Tailwind admite la lista de clases permitidas basada en patrones para situaciones en las que necesitas permitir una gran cantidad de clases:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    safelist: [
        'text-2xl',
        'text-3xl',
        {
            pattern: /bg-(red|green|blue)-(100|200|300)/,
        },
    ],
    // ...
}

Los patrones solo pueden coincidir con nombres de utilidades base como /bg-rojo-.+/ , y no coincidirán si el patrón incluye un modificador de variante como /hover:bg-rojo-.+/ .

Si deseas obligar a Tailwind a generar variantes para las clases coincidentes, inclúyelas utilizando la opción variants :

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    safelist: [
        'text-2xl',
        'text-3xl',
        {
            pattern: /bg-(red|green|blue)-(100|200|300)/,
            variants: ['lg', 'hover', 'focus', 'lg:hover'],
        },
    ],
    // ...
}

Descarte de clases

Dado que Tailwind utiliza un enfoque muy simple para detectar nombres de clases en tu contenido, es posible que descubras que se generan algunas clases que en realidad no necesitas.

Por ejemplo, este HTML seguiría generando la clase container, aunque en realidad no se esté utilizando esa clase:

<div class="text-lg leading-8 text-gray-600">
    Bla bla bla bla container, bla bla bla bla.
</div>

También es posible que desees evitar que Tailwind genere ciertas clases cuando esas clases entrarían en conflicto con algún CSS existente, pero no deseas agregar un prefijo a todas tus clases de Tailwind.

En estas situaciones, puedes utilizar la opción de lista negra (blocklist) para indicarle a Tailwind que ignore clases específicas que detecte en tu contenido:

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ['./pages/**/*.{html,js}', './components/**/*.{html,js}'],
    blocklist: ['container', 'collapse'],
    // ...
}

La opción de lista negra (blocklist) solo afecta al CSS que generaría Tailwind, no al CSS personalizado que hayas creado tú mismo o que estés importando desde otra biblioteca.

A diferencia de la lista de clases permitidas (safelist), la opción de lista negra solo admite cadenas y no puedes bloquear clases utilizando expresiones regulares.

Transformación de archivos fuente

Si estás creando contenido en un formato que se compila a HTML (como Markdown), a menudo tiene sentido compilar ese contenido a HTML antes de analizarlo en busca de nombres de clases.

Utiliza la opción content.transform para transformar cualquier contenido que coincida con una extensión de archivo específica antes de extraer las clases:

// tailwind.config.js
const remark = require('remark')

module.exports = {
    content: {
        files: ['./src/**/*.{html,md}'],
        transform: {
            md: (content) => {
                return remark().process(content)
            },
        },
    },
    // ...
}

Cuando uses content.transform , deberás proporcionar tus rutas de origen utilizando content.files en lugar de un arreglo de nivel superior bajo content.

Personalización de lógica de extracción

Utiliza la opción extract para reemplazar la lógica que Tailwind utiliza para detectar nombres de clases en extensiones de archivo específicas:

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: {
        files: ['./src/**/*.{html,wtf}'],
        extract: {
            wtf: (content) => {
                return content.match(/[^<>"'`\s]*/)
            },
        },
    },
    // ...
}

Esta es una característica avanzada y la mayoría de los usuarios no la necesitarán; la lógica de extracción predeterminada en Tailwind funciona extremadamente bien para casi todos los proyectos.

Al igual que con la transformación, al usar content.extract , deberás proporcionar tus rutas de origen utilizando content.files en lugar de un arreglo de nivel superior bajo content.

Solución de problemas

Las clases no se generan

Si Tailwind no está generando clases, asegúrate de que tu configuración de contenido sea correcta y coincida con todos los archivos de origen adecuados.

Un error común es omitir una extensión de archivo, por ejemplo, si estás utilizando “jsx” en lugar de “js” para tus componentes de React:

// tailwind.config.js
module.exports = {
    content: [
        './src/**/*.{html,js}', // <- no funcionará
        './src/**/*.{html,js,jsx}', // <- correcto
    ],
    // ...
}

Otro error común es crear una nueva carpeta en medio del proyecto que no estaba cubierta originalmente y olvidar agregarla a tu configuración.

También podría ser que estés intentando usar nombres de clases dinámicos, lo cual no funcionará porque Tailwind en realidad no evalúa tu código fuente y solo puede detectar cadenas de clases estáticas y completas.

Estilos que se reconstruyen en un bucle infinito

Si notas que tu CSS se está generando repetidamente sin parar, es probable que sea porque la herramienta que usas para construir tu proyecto no entiende la opción glob cuando se registran las dependencias de PostCSS.

Muchas de estas herramientas, como webpack, no comprenden esta opción, lo que significa que solo podemos decirles que estén atentas a archivos específicos o carpetas completas. No podemos pedirles, por ejemplo, que solo observen archivos *.html en una carpeta en particular.

Entonces, si cualquier archivo en esas carpetas cambia mientras construyes tu CSS, provocará una reconstrucción, incluso si el archivo que cambió no coincide con la extensión especificada en tu patrón (glob).

// tailwind.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
    content: [
        // With some build tools, your CSS will rebuild
        // any time *any* file in `src` changes.
        './src/**/*.{html,js}',
    ],
    // ...
}

Así que si estás observando cambios en src/**/*.html , pero estás escribiendo tu archivo de salida CSS en src/css/styles.css , podrías entrar en un bucle de reconstrucción infinito con algunas herramientas.

Idealmente, podríamos advertirte sobre esto en la consola, pero muchas herramientas lo admiten perfectamente (incluida nuestra propia herramienta CLI), y no tenemos una forma confiable de detectar qué herramienta de construcción estás utilizando.

Para resolver este problema, utiliza rutas más específicas en tu configuración de contenido, asegurándote de incluir solo directorios que no cambiarán cuando se construya tu CSS:

module.exports = {
    content: [
        './src/**/*.{html,js}', // <- evitar esto y reemplazarlo por las siguientes lineas
        './src/pages/**/*.{html,js}',
        './src/components/**/*.{html,js}',
        './src/layouts/**/*.{html,js}',
        './src/index.html',
    ],
    // ...
}

Si es necesario, ajusta la estructura de directorios de tu proyecto para asegurarte de que puedas apuntar a tus archivos de plantilla sin atrapar accidentalmente tu archivo CSS u otros archivos de construcción, como archivos de manifiesto.

Si no puedes cambiar la configuración de tu contenido o la estructura de directorios de tu proyecto de ninguna manera, la mejor opción es compilar tu CSS por separado utilizando una herramienta que admita completamente las búsquedas con glob . Recomendamos utilizar Tailwind CLI, que es una herramienta rápida, simple y diseñada específicamente para compilar tu CSS con Tailwind.

No funciona correctamente

Si estás experimentando problemas extraños y difíciles de describir con la salida, o simplemente sientes que las cosas no están funcionando en absoluto, es probable que se deba a que tu herramienta de construcción no admite correctamente (o en absoluto) los mensajes de dependencia de PostCSS. Un ejemplo conocido de esto en la actualidad es Stencil.

Cuando tengas este tipo de problemas, te recomendamos utilizar Tailwind CLI para compilar tu CSS por separado en lugar de intentar integrar Tailwind en tus herramientas de desarrollo existentes.

Puedes utilizar paquetes como npm-run-all o concurrently para compilar tu CSS junto con tu comando de desarrollo habitual mediante la adición de algunos scripts a tu proyecto, como este:

// package.json
{
    // ...
    "scripts": {
        "start": "concurrently \"npm run start:css\" \"react-scripts start\"",
        "start:css": "tailwindcss -o src/tailwind.css --watch",
        "build": "npm run build:css && react-scripts build",
        "build:css": "NODE_ENV=production tailwindcss -o src/tailwind.css -m"
    }
}