Primeros pasos
Migración de tus proyectos de Tailwind CSS de v3 a v4.
Tailwind CSS v4.0 es una nueva versión principal del framework, por lo que aunque hemos trabajado muy duro para minimizar los cambios disruptivos, algunas actualizaciones son necesarias. Esta guía describe todos los pasos necesarios para actualizar tus proyectos de v3 a v4.
Tailwind CSS v4.0 está diseñado para Safari 16.4+, Chrome 111+ y Firefox 128+. Si necesitas dar soporte a navegadores más antiguos, quédate con v3.4 hasta que cambien tus requisitos de soporte de navegador.
Si deseas actualizar un proyecto de v3 a v4, puedes utilizar nuestra herramienta de actualización para realizar la gran mayoría del trabajo pesado por ti:
$ npx @tailwindcss/upgradePara la mayoría de los proyectos, la herramienta de actualización automatizará todo el proceso de migración, incluyendo la actualización de tus dependencias, la migración de tu archivo de configuración a CSS y el manejo de cualquier cambio en tus archivos de plantilla.
La herramienta de actualización requiere Node.js 20 o superior, así que asegúrate de que tu entorno esté actualizado antes de ejecutarla.
Recomendamos ejecutar la herramienta de actualización en una nueva rama, luego revisar cuidadosamente el diff y probar tu proyecto en el navegador para asegurarte de que todos los cambios se vean correctos. Es posible que debas ajustar algunas cosas a mano en proyectos complejos, pero la herramienta te ahorrará mucho tiempo de todos modos.
También es una buena idea revisar todos los cambios disruptivos en v4 y obtener una buena comprensión de lo que ha cambiado, en caso de que haya otras cosas que debas actualizar en tu proyecto que la herramienta de actualización no detecte.
En v3, el paquete tailwindcss era un plugin de PostCSS, pero en v4 el plugin de PostCSS vive en un paquete dedicado @tailwindcss/postcss.
Además, en v4 las importaciones y el prefijado del proveedor ahora se manejan automáticamente por ti, por lo que puedes eliminar postcss-import y autoprefixer si están en tu proyecto:
export default { plugins: { "postcss-import": {}, tailwindcss: {}, autoprefixer: {}, "@tailwindcss/postcss": {}, },};Si estás usando Vite, te recomendamos migrar del plugin de PostCSS a nuestro nuevo plugin de Vite dedicado para mejorar el rendimiento y obtener la mejor experiencia de desarrollo:
import { defineConfig } from "vite";import tailwindcss from "@tailwindcss/vite";export default defineConfig({ plugins: [ tailwindcss(), ],});En v4, Tailwind CLI vive en un paquete dedicado @tailwindcss/cli. Actualiza cualquiera de tus comandos de construcción para usar el nuevo paquete en su lugar:
npx tailwindcss -i input.css -o output.cssnpx @tailwindcss/cli -i input.css -o output.cssAquí tienes una lista completa de todos los cambios disruptivos en Tailwind CSS v4.0.
Nuestra herramienta de actualización manejará la mayoría de estos cambios por ti automáticamente, por lo que te recomendamos encarecidamente que la uses si puedes.
Tailwind CSS v4.0 está diseñado para navegadores modernos y apunta a Safari 16.4, Chrome 111 y Firefox 128. Dependemos de características modernas de CSS como @property y color-mix() para las características principales del framework, y Tailwind CSS v4.0 no funcionará en navegadores antiguos.
Si necesitas dar soporte a navegadores antiguos, te recomendamos seguir con v3.4 por ahora. Estamos explorando activamente un modo de compatibilidad para ayudar a las personas a actualizar antes, del cual esperamos compartir más noticias en el futuro.
En v4 importas Tailwind usando una declaración @import de CSS normal, no usando las directivas @tailwind que usabas en v3:
@tailwind base;@tailwind components;@tailwind utilities;@import "tailwindcss";Hemos eliminado cualquier utilidad que estuviera obsoleta en v3 y que no haya estado documentada durante varios años. Aquí hay una lista de lo que se ha eliminado junto con la alternativa moderna:
| Obsoleta | Reemplazo |
|---|---|
bg-opacity-* | Usa modificadores de opacidad como bg-black/50 |
text-opacity-* | Usa modificadores de opacidad como text-black/50 |
border-opacity-* | Usa modificadores de opacidad como border-black/50 |
divide-opacity-* | Usa modificadores de opacidad como divide-black/50 |
ring-opacity-* | Usa modificadores de opacidad como ring-black/50 |
placeholder-opacity-* | Usa modificadores de opacidad como placeholder-black/50 |
flex-shrink-* | shrink-* |
flex-grow-* | grow-* |
overflow-ellipsis | text-ellipsis |
decoration-slice | box-decoration-slice |
decoration-clone | box-decoration-clone |
Hemos renombrado las siguientes utilidades en v4 para hacerlas más consistentes y predecibles:
| v3 | v4 |
|---|---|
shadow-sm | shadow-xs |
shadow | shadow-sm |
drop-shadow-sm | drop-shadow-xs |
drop-shadow | drop-shadow-sm |
blur-sm | blur-xs |
blur | blur-sm |
backdrop-blur-sm | backdrop-blur-xs |
backdrop-blur | backdrop-blur-sm |
rounded-sm | rounded-xs |
rounded | rounded-sm |
outline-none | outline-hidden |
ring | ring-3 |
Hemos renombrado las escalas predeterminadas de sombra, radio y desenfoque para asegurarnos de que cada utilidad tenga un valor con nombre. Las versiones "simples" todavía funcionan por compatibilidad con versiones anteriores, pero las utilidades <utility>-sm se verán diferentes a menos que se actualicen a sus respectivas versiones <utility>-xs.
Para actualizar tu proyecto para estos cambios, reemplaza todas las utilidades de v3 con sus versiones de v4:
<input class="shadow-sm" /><input class="shadow-xs" /><input class="shadow" /><input class="shadow-sm" />La utilidad outline ahora establece outline-width: 1px de forma predeterminada para ser más consistente con las utilidades de borde y anillo. Además, todas las utilidades outline-<number> establecen outline-style a solid de forma predeterminada, omitiendo la necesidad de combinarlas con outline:
<input class="outline outline-2" /><input class="outline-2" />La utilidad outline-none anteriormente no establecía realmente outline-style: none, sino que establecía un contorno invisible que aún se mostraría en el modo de colores forzados por razones de accesibilidad.
Para hacer esto más claro, hemos renombrado esta utilidad a outline-hidden y hemos añadido una nueva utilidad outline-none que realmente establece outline-style: none.
Para actualizar tu proyecto para este cambio, reemplaza cualquier uso de outline-none con outline-hidden:
<input class="focus:outline-none" /><input class="focus:outline-hidden" />En v3, la utilidad ring añadía un anillo de 3px. Hemos cambiado esto en v4 a 1px para que sea consistente con los bordes y contornos.
Para actualizar tu proyecto para este cambio, reemplaza cualquier uso de ring con ring-3:
<input class="ring ring-blue-500" /><input class="ring-3 ring-blue-500" />Hemos cambiado el selector utilizado por las utilidades space-x-* y space-y-* para abordar problemas graves de rendimiento en páginas grandes:
/* Antes */.space-y-4 > :not([hidden]) ~ :not([hidden]) { margin-top: 1rem;}/* Ahora */.space-y-4 > :not(:last-child) { margin-bottom: 1rem;}Es posible que veas cambios en tu proyecto si alguna vez estuviste usando estas utilidades con elementos en línea, o si estuviste agregando otros márgenes a los elementos hijos para ajustar su espaciado.
Si este cambio causa algún problema en tu proyecto, te recomendamos migrar a un diseño flex o grid y usar gap en su lugar:
<div class="space-y-4 p-4"><div class="flex flex-col gap-4 p-4"> <label for="name">Name</label> <input type="text" name="name" /></div>Hemos cambiado el selector utilizado por las utilidades divide-x-* y divide-y-* para abordar problemas graves de rendimiento en páginas grandes:
/* Antes */.divide-y-4 > :not([hidden]) ~ :not([hidden]) { border-top-width: 4px;}/* Ahora */.divide-y-4 > :not(:last-child) { border-bottom-width: 4px;}Es posible que veas cambios en tu proyecto si alguna vez estuviste usando estas utilidades con elementos en línea, si estuviste agregando otros márgenes/rellenos a los elementos hijos para ajustar su espaciado, o ajustando los bordes de elementos hijos específicos.
En v3, anular parte de un gradiente con una variante "reiniciaba" todo el gradiente, por lo que en este ejemplo el color to-* sería transparente en modo oscuro en lugar de amarillo:
<div class="bg-gradient-to-r from-red-500 to-yellow-400 dark:from-blue-500"> <!-- ... --></div>En v4, estos valores se conservan, lo que es más consistente con el funcionamiento de otras utilidades en Tailwind.
Esto significa que es posible que debas usar explícitamente via-none si deseas "desactivar" un gradiente de tres paradas para volver a un gradiente de dos paradas en un estado específico:
<div class="bg-linear-to-r from-red-500 via-orange-400 to-yellow-400 dark:via-none dark:from-blue-500 dark:to-teal-400"> <!-- ... --></div>En v3, la utilidad container tenía varias opciones de configuración como center y padding que ya no existen en v4.
Para personalizar la utilidad container en v4, extiéndela usando la directiva @utility:
@utility container { margin-inline: auto; padding-inline: 2rem;}En v3, las utilidades border-* y divide-* usaban de forma predeterminada el color gray-200 configurado. Hemos cambiado esto a currentColor en v4 para que Tailwind sea menos opinativo y coincida con los valores predeterminados del navegador.
Para actualizar tu proyecto para este cambio, asegúrate de especificar un color en cualquier lugar donde estés usando una utilidad border-* o divide-*:
<div class="border border-gray-200 px-2 py-3 ..."> <!-- ... --></div>Como alternativa, añade estos estilos base a tu proyecto para conservar el comportamiento de v3:
@layer base { *, ::after, ::before, ::backdrop, ::file-selector-button { border-color: var(--color-gray-200, currentColor); }}Hemos cambiado el ancho de la utilidad ring de 3px a 1px y hemos cambiado el color predeterminado de blue-500 a currentColor para que las cosas sean más consistentes con las utilidades border-*, divide-* y outline-*.
Para actualizar tu proyecto para estos cambios, reemplaza cualquier uso de ring con ring-3:
<button class="focus:ring ..."><button class="focus:ring-3 ..."> <!-- ... --></button>Luego, asegúrate de añadir ring-blue-500 en cualquier lugar donde dependieras del color de anillo predeterminado:
<button class="focus:ring-3 focus:ring-blue-500 ..."> <!-- ... --></button>Como alternativa, añade estas variables de tema a tu CSS para conservar el comportamiento de v3:
@theme { --default-ring-width: 3px; --default-ring-color: var(--color-blue-500);}Ten en cuenta que estas variables solo se admiten por razones de compatibilidad y no se consideran un uso idiomático de Tailwind CSS v4.0.
Hemos realizado algunos pequeños cambios en los estilos base de Preflight en v4:
En v3, el texto del marcador de posición usaba de forma predeterminada el color gray-400 configurado. Hemos simplificado esto en v4 para usar simplemente el color del texto actual con un 50% de opacidad.
Es probable que ni siquiera notes este cambio (incluso podría hacer que tu proyecto se vea mejor), pero si deseas conservar el comportamiento de v3, añade este CSS a tu proyecto:
@layer base { input::placeholder, textarea::placeholder { color: var(--color-gray-400); }}Los botones ahora usan cursor: default en lugar de cursor: pointer para coincidir con el comportamiento predeterminado del navegador.
Si deseas seguir usando cursor: pointer de forma predeterminada, añade estos estilos base a tu CSS:
@layer base { button:not(:disabled), [role="button"]:not(:disabled) { cursor: pointer; }}Preflight ahora restablece los márgenes en los elementos <dialog> para ser consistente con cómo se restablecen otros elementos.
Si aún deseas que los diálogos estén centrados de forma predeterminada, añade este CSS a tu proyecto:
@layer base { dialog { margin: auto; }}Las clases de visualización como block o flex ya no tienen prioridad sobre el atributo hidden en un elemento. Elimina el atributo hidden si deseas que un elemento sea visible para el usuario. Ten en cuenta que esto no se aplica a hidden="until-found".
Los prefijos ahora se ven como variantes y siempre están al principio del nombre de la clase:
<div class="tw:flex tw:bg-red-500 tw:hover:bg-red-600"> <!-- ... --></div>Al usar un prefijo, aún debes configurar las variables de tu tema como si no estuvieras usando un prefijo:
@import "tailwindcss" prefix(tw);@theme { --font-display: "Satoshi", "sans-serif"; --breakpoint-3xl: 120rem; --color-avocado-100: oklch(0.99 0 0); --color-avocado-200: oklch(0.98 0.04 113.22); --color-avocado-300: oklch(0.94 0.11 115.03); /* ... */}Las variables CSS generadas sí incluirán un prefijo para evitar conflictos con las variables existentes en tu proyecto:
:root { --tw-font-display: "Satoshi", "sans-serif"; --tw-breakpoint-3xl: 120rem; --tw-color-avocado-100: oklch(0.99 0 0); --tw-color-avocado-200: oklch(0.98 0.04 113.22); --tw-color-avocado-300: oklch(0.94 0.11 115.03); /* ... */}En v3 podías marcar una utilidad como importante colocando un ! al principio del nombre de la utilidad (pero después de cualquier variante). En v4 debes colocar el ! al final del nombre de la clase en su lugar:
<div class="flex! bg-red-500! hover:bg-red-600/50!"> <!-- ... --></div>La forma antigua todavía se admite por compatibilidad, pero está obsoleta.
En v3, cualquier clase personalizada que definieras dentro de @layer utilities o @layer components sería detectada por Tailwind como una clase de utilidad real y funcionaría automáticamente con variantes como hover, focus o lg, con la diferencia de que @layer components siempre vendría primero en la hoja de estilos generada.
En v4 estamos usando capas de cascada nativas y ya no secuestramos la regla-at @layer, por lo que hemos introducido la API @utility como reemplazo:
@layer utilities { .tab-4 { tab-size: 4; }}@utility tab-4 { tab-size: 4;}Las utilidades personalizadas ahora también se ordenan en función de la cantidad de propiedades que definen. Esto significa que las utilidades de componentes como esta .btn pueden ser sobrescritas por otras utilidades de Tailwind sin configuración adicional:
@layer components { .btn { border-radius: 0.5rem; padding: 0.5rem 1rem; background-color: ButtonFace; }}@utility btn { border-radius: 0.5rem; padding: 0.5rem 1rem; background-color: ButtonFace;}Obtén más información sobre el registro de utilidades personalizadas en la documentación para añadir utilidades personalizadas.
En v3, las variantes apiladas se aplicaban de derecha a izquierda, pero en v4 las hemos actualizado para que se apliquen de izquierda a derecha para parecerse más a la sintaxis CSS.
Para actualizar tu proyecto para este cambio, invierte el orden de cualquier variante apilada sensible al orden en tu proyecto:
<ul class="py-4 first:*:pt-0 last:*:pb-0"><ul class="py-4 *:first:pt-0 *:last:pb-0"> <li>One</li> <li>Two</li> <li>Three</li></ul>Es probable que tengas muy pocas de estas, si es que tienes alguna; la variante de hijo directo (*) y cualquier variante del plugin de tipografía (prose-headings) son las más probables que estés usando, e incluso entonces solo es si las has apilado con otras variantes.
En v3 podías usar variables CSS como valores arbitrarios sin var(), pero las actualizaciones recientes de CSS significan que esto a menudo puede ser ambiguo, por lo que hemos cambiado la sintaxis para esto en v4 para usar paréntesis en lugar de corchetes.
Para actualizar tu proyecto para este cambio, reemplaza el uso de la antigua sintaxis abreviada de variables con la nueva sintaxis abreviada de variables:
<div class="bg-[--brand-color]"></div><div class="bg-(--brand-color)"></div>Las comas se reemplazaban previamente con espacios en las utilidades grid-cols-*, grid-rows-* y object-* dentro de valores arbitrarios. Este comportamiento especial existía en Tailwind CSS v3 por compatibilidad con v2. Este comportamiento ya no existe en v4.0 y se deben usar guiones bajos para representar espacios.
Para actualizar tu proyecto para este cambio, reemplaza el uso de comas que debían ser espacios con guiones bajos:
<div class="grid-cols-[max-content,auto]"></div><div class="grid-cols-[max-content_auto]"></div>En v4 hemos actualizado la variante hover para que solo se aplique cuando el dispositivo de entrada principal admita hover:
@media (hover: hover) { .hover\:underline:hover { text-decoration: underline; }}Esto puede crear problemas si has creado tu sitio de una manera que dependa de que los dispositivos táctiles activen el hover al tocar. Si esto es un problema para ti, puedes anular la variante hover con tu propia variante que use la implementación antigua:
@custom-variant hover (&:hover);Por lo general, recomendamos tratar la funcionalidad hover como una mejora y no depender de ella para que tu sitio funcione, ya que los dispositivos táctiles realmente no tienen la capacidad de hacer hover.
Las utilidades transition y transition-colors ahora incluyen la propiedad outline-color.
Esto significa que si estabas añadiendo un contorno con un color personalizado en el foco, verás la transición de color desde el color predeterminado. Para evitar esto, asegúrate de establecer el color del contorno incondicionalmente, o establécelo explícitamente para ambos estados:
<button class="transition hover:outline-2 hover:outline-cyan-500"></button><button class="outline-cyan-500 transition hover:outline-2"></button>Las utilidades rotate-*, scale-* y translate-* ahora se basan en las propiedades individuales rotate, scale y translate en CSS. Normalmente esto no debería afectar el comportamiento, pero hay un par de casos a tener en cuenta:
Anteriormente habrías podido "restablecer" tus utilidades de rotación, escala y traslación a través de transform-none. Esto ya no funciona y tendrás que restablecer las propiedades individuales en su lugar:
<button class="scale-150 focus:transform-none"></button><button class="scale-150 focus:scale-none"></button>Si personalizas la lista de propiedades con transición e incluyes transform (por ejemplo, escribiendo transition-[opacity,transform]), estas utilidades ya no tendrán transiciones. Para solucionar esto, incluye las propiedades individuales en la lista. Por ejemplo, si deseas aplicar transiciones a los cambios al usar las utilidades opacity-* y scale-*, debes usar transition-[opacity,scale] en su lugar.
<button class="transition-[opacity,transform] hover:scale-150"></button><button class="transition-[opacity,scale] hover:scale-150"></button>En v3 había una opción corePlugins que podías usar para desactivar por completo ciertas utilidades en el framework. Esto ya no se admite en v4.
Dado que v4 incluye variables CSS para todos los valores de tu tema, recomendamos usar esas variables en lugar de la función theme() siempre que sea posible:
.my-class { background-color: theme(colors.red.500); background-color: var(--color-red-500);}Para los casos en los que aún necesites usar la función theme() (como en consultas de medios donde no se admiten variables CSS), debes usar el nombre de la variable CSS en lugar de la antigua notación de puntos:
@media (width >= theme(screens.xl)) {@media (width >= theme(--breakpoint-xl)) { /* ... */}Los archivos de configuración de JavaScript todavía se admiten por compatibilidad con versiones anteriores, pero ya no se detectan automáticamente en v4.
Si aún necesitas usar un archivo de configuración de JavaScript, puedes cargarlo explícitamente usando la directiva @config:
@config "../../tailwind.config.js";Las opciones corePlugins, safelist y separator de la configuración basada en JavaScript no se admiten en v4.0. Para incluir utilidades en la lista de permitidas en v4, usa @source inline().
En v3 exportamos una función resolveConfig que podías usar para convertir tu configuración basada en JavaScript en un objeto plano que pudieras usar en tu otro JavaScript.
Hemos eliminado esto en v4 con la esperanza de que la gente pueda usar directamente las variables CSS que generamos, lo cual es mucho más simple y reducirá significativamente el tamaño de tu paquete.
Por ejemplo, la popular biblioteca Motion para React te permite animar hacia y desde valores de variables CSS:
<motion.div animate={{ backgroundColor: "var(--color-blue-500)" }} />Si necesitas acceder a un valor de variable CSS resuelto en JS, puedes usar getComputedStyle para obtener el valor de una variable de tema en la raíz del documento:
let styles = getComputedStyle(document.documentElement);let shadow = styles.getPropertyValue("--shadow-xl");En v4, las hojas de estilo que se empaquetan por separado de tu archivo CSS principal (por ejemplo, archivos de módulos CSS, bloques <style> en Vue, Svelte o Astro, etc.) no tienen acceso a las variables de tema, utilidades personalizadas y variantes personalizadas definidas en otros archivos.
Para que estas definiciones estén disponibles en estos contextos, usa @reference para importarlas sin duplicar ningún CSS en tu paquete:
<template> <h1>Hello world!</h1></template><style> @reference "../../app.css"; h1 { @apply text-2xl font-bold text-red-500; }</style>Como alternativa, puedes usar tus variables de tema CSS directamente en lugar de usar @apply, lo que también mejorará el rendimiento ya que Tailwind no necesitará procesar estos estilos:
<template> <h1>Hello world!</h1></template><style> h1 { color: var(--text-red-500); }</style>Puedes encontrar más documentación sobre el uso de Tailwind con módulos CSS.
Tailwind CSS v4.0 no está diseñado para ser utilizado con preprocesadores CSS como Sass, Less o Stylus. Piensa en Tailwind CSS en sí mismo como tu preprocesador: no deberías usar Tailwind con Sass por la misma razón por la que no usarías Sass con Stylus. Debido a esto, no es posible usar Sass, Less o Stylus para tus hojas de estilo o bloques <style> en Vue, Svelte, Astro, etc.
Obtén más información en la documentación de compatibilidad.