Capítulo 14 de 29
Tailwind v4 is a new engine (Lightning CSS-based) with a CSS-first configuration model — most v3→v4 migration is handled by npx @tailwindcss/upgrade (Node 20+, run on a branch, review the diff), but there's a long list of behavioral/naming changes worth knowing even when the tool does the mechanical work.
npx @tailwindcss/upgrade migrates dependencies, converts tailwind.config.js to CSS, and updates template files automatically for most projects — run it on a branch and review the diff rather than trusting it blindly on a complex project.@tailwindcss/postcss (drop postcss-import/autoprefixer, both now automatic); Vite users should switch to the dedicated @tailwindcss/vite plugin; the CLI moved to @tailwindcss/cli.@import "tailwindcss" replaces @tailwind base/components/utilities — a single regular CSS import instead of three custom directives.@property and color-mix(), so older browsers need to stay on v3.4.| Deprecated (removed) | Replacement |
|---|---|
bg-opacity-*, text-opacity-*, border-opacity-*, divide-opacity-*, ring-opacity-*, placeholder-opacity-* | Opacity modifier, e.g. bg-black/50 |
flex-shrink-* | shrink-* |
flex-grow-* | grow-* |
overflow-ellipsis | text-ellipsis |
decoration-slice / decoration-clone | box-decoration-slice / box-decoration-clone |
| v3 | v4 | Why |
|---|---|---|
shadow-sm → shadow | shadow-xs → shadow-sm | Shadow/radius/blur scales renamed so every step has an explicit name; bare shadow/rounded/blur still work but now render like the old -sm step |
drop-shadow-sm → drop-shadow | drop-shadow-xs → drop-shadow-sm | Same renumbering |
blur-sm → blur | blur-xs → blur-sm | Same renumbering |
backdrop-blur-sm → backdrop-blur | backdrop-blur-xs → backdrop-blur-sm | Same renumbering |
rounded-sm → rounded | rounded-xs → rounded-sm | Same renumbering |
outline-none | outline-hidden | outline-none in v3 didn't actually set outline-style: none (kept an invisible outline for forced-colors accessibility) — v4's outline-hidden preserves that behavior, and a new outline-none now genuinely sets outline-style: none |
outline outline-2 | outline-2 (alone) | outline-<n> now implies outline-style: solid; outline alone now also sets outline-width: 1px |
ring (3px) | ring-3 | Default ring width dropped from 3px to 1px for consistency with border/outline; also default ring color changed from blue-500 to currentColor |
space-x-*/space-y-* and divide-x-*/divide-y-* switched from a :not([hidden]) ~ :not([hidden]) sibling selector to :not(:last-child) for performance on large pages — can shift behavior with inline elements or hand-tuned child margins; migrating to flex/grid + gap-* avoids the whole selector question.from-* in a variant (e.g. dark:from-blue-500) used to blow away to-*/via-* too; in v4 the other stops persist, so explicitly use via-none if you need to collapse a three-stop gradient back to two stops in a specific state.container utility lost its config options (center, padding) — customize it via @utility container { margin-inline: auto; padding-inline: 2rem; } instead.border-*/divide-* color changed from gray-200 to currentColor — always specify a color explicitly now, or restore old behavior with a @layer base rule setting border-color: var(--color-gray-200, currentColor).gray-400); buttons default to cursor: default (was pointer); <dialog> margins are reset (add margin: auto in @layer base to restore centering); the hidden attribute now always wins over display utilities like block/flex.prefix(tw)) now behave like a variant at the very start of the class (tw:flex, tw:hover:bg-red-600) instead of a config-driven class-name prefix; @theme is still written unprefixed, but generated CSS variables are prefixed (--tw-color-...).!important modifier moves to the end of the class (bg-red-500!, hover:bg-red-600/50!) instead of the start — old leading ! still works but is deprecated.@layer utilities/@layer components class hijacking is gone — use @utility instead; custom utilities now sort by property count, so a .btn-style utility can be overridden by more specific Tailwind utilities without extra config.first:*:pt-0 → *:first:pt-0).bg-[--brand-color] → bg-(--brand-color) (ambiguity with newer CSS syntax forced the change).grid-cols-*, grid-rows-*, object-*) are no longer auto-converted to spaces — use underscores explicitly (grid-cols-[max-content_auto], not [max-content,auto]).hover: now respects (hover: hover), so it no longer fires on tap for touch-only devices by default — restore old always-fires behavior with @custom-variant hover (&:hover); if a project depends on it (not recommended long-term).transition/transition-colors now include outline-color — an outline color set only inside a state variant will visibly transition from the default; set the color unconditionally instead.rotate-*/scale-*/translate-* are now individual CSS properties, not part of a combined transform value: transform-none no longer resets them (reset the individual utility instead, e.g. scale-none), and a custom transition-[...] list must name the individual properties (transition-[opacity,scale], not transition-[opacity,transform]) to keep them animating.corePlugins config option is gone — no more disabling whole utility families via config.theme() function: prefer the generated var(--token) CSS variables; where theme() is still required (e.g. inside a media query, which can't take a CSS variable), use the CSS variable name instead of v3's dot notation (theme(--breakpoint-xl), not theme(screens.xl)).@config "./tailwind.config.js"; but are no longer auto-detected; corePlugins/safelist/separator config options aren't supported at all in v4 (use @source inline() for safelisting).resolveConfig (JS) removed — read theme values as CSS variables (var(--color-blue-500)) or via getComputedStyle instead of a flattened JS config object.<style>) no longer implicitly see theme/custom-utility/custom-variant definitions from other files — add @reference "<path>"; before using @apply, or switch to var(--token) (also faster, since Tailwind skips processing that file).ring→ring-3, outline-none→outline-hidden) are exactly the kind of change that's easy to miss by eye.-sm-labeled utilities across shadow/blur/radius/backdrop-blur all quietly shrank a step in v4 — search for these four families specifically even after running the tool.theme(), resolveConfig, corePlugins, or hover-always-fires-on-tap: these are the explicit "you need a decision" migration points, not automatic.@theme/CSS variables are the v4 replacement for tailwind.config.js and the theme() function.@reference, @config, @utility, important import flag — the v4-native mechanisms several of these migrations move toward.