Español
consistent-variant-order
Regla de oxlint que escribe las cadenas de variantes de Tailwind CSS de afuera hacia adentro — dark:hover:, no hover:dark: — y reescribe el resto, con autofix.
De un vistazo
| Autofix | Sugerencias en el editor | Design system | Opciones |
|---|---|---|---|
| Sí | Sí | Opcional — se usa si hay entryPoint | entryPoint, order |
Qué hace esta regla
Reordena los prefijos de variants dentro de una sola clase para que la cadena se escriba siempre igual. hover:dark:bg-red y dark:hover:bg-red producen el mismo CSS en Tailwind v4, pero un orden inconsistente ensucia grep, code reviews y diffs. Esta regla elige un orden canónico y reescribe todo para que coincida, con autofix sobre el primer ofensor y sugerencias de editor sobre el resto.
El orden va de afuera hacia adentro, como escriben las cadenas las docs de Tailwind y shadcn/ui:
- Dónde está la página: breakpoints (
sm…2xl,min-*,max-*),supports-*,motion-*,contrast-*,forced-colors,pointer-*,portrait/landscape,dark, container queries (@md,@min-*),print,starting,ltr/rtl. - En qué ancestro o hermano está el elemento:
group-*,peer-*,in-*. - Qué es el elemento:
aria-*,data-*,has-*,not-*. - Cómo se está usando:
visited,target,hover,focus,focus-within,focus-visible,active. - Su estado de formulario:
enabled,disabled,checked, …read-only,open,inert. - Dónde está entre sus hermanos:
first,last,only,odd,even,*-of-type,nth-*,empty.
Los breakpoints entre sí, las container queries entre sí y las variants dentro del paso 2 o dentro del paso 3 conservan el orden en que las escribiste, así que data-[a]:data-[b]: y data-[b]:data-[a]: quedan como están. not-X se ordena como X (not-sm:hover:). Una variant para la que la regla no tiene lugar — una que define tu proyecto con @custom-variant — nunca se mueve, y nada se mueve a través de ella.
Los pseudo-elements (before, after, file, placeholder, selection, marker, backdrop, first-line, first-letter, details-content) quedan siempre pinneados innermost — lo más cerca posible de la utility — porque en Tailwind v4 un pseudo-element puesto antes de una variant que selecciona elemento produce CSS roto del estilo &::before { &>svg { … } }. Las variants que apuntan el selector a otro elemento (*, **, [&>svg]) son barreras: nada se reordena a través de ellas, porque hover:[&>svg]: (&:hover > svg) y [&>svg]:hover: (& > svg:hover) estilan elementos distintos.
DS-opcional — el orden es el mismo con o sin settings.tailwindcss.entryPoint. Lo que aporta el design system es qué son las variants propias de tu proyecto, a partir de los selectores que genera: @custom-variant thumb (&::-webkit-slider-thumb) queda pinneada innermost como before:, @custom-variant child (& > *) se vuelve una barrera, y un breakpoint que agregas con --breakpoint-3xl se ordena con los demás. Sin él, la regla usa las listas fijas de arriba, y un entry point faltante se tolera silenciosamente (no-contradicting-variants es la otra regla que hace esto).
Opciones
order
string[], opcional.
Lista de prioridad personalizada, que reemplaza el orden built-in. Los variants aparecen en el orden que listas; lo que no listas ordena después, en su posición original. Úsalo cuando tu team tiene un house style distinto al default (por ejemplo, quieres los estados antes que los breakpoints). El pin de pseudo-elements y las barreras siguen aplicando sin importar tu lista.
jsonc
{
"tailwindcss/consistent-variant-order": ["error", { "order": ["hover", "focus", "sm", "md"] }]
}entryPoint
string, opcional.
Override por regla de settings.tailwindcss.entryPoint. Misma semántica que el setting a nivel proyecto; casi nunca se necesita.
Ejemplos
✗ Incorrecto
tsx
// estado antes que breakpoint
<div className="hover:sm:flex" />
// → <div className="sm:hover:flex" />
// estado antes que color scheme
<div className="hover:dark:text-white" />
// → <div className="dark:hover:text-white" />
// cómo se usa antes que qué es
<div className="focus:data-[state=open]:bg-accent" />
// → <div className="data-[state=open]:focus:bg-accent" />
// pseudo-element antes que variant de elemento — roto en Tailwind v4
<div className="before:[&>svg]:text-red-500" />
// → <div className="[&>svg]:before:text-red-500" />✓ Correcto
tsx
<div className="sm:hover:flex" />
<div className="dark:hover:text-white" />
<div className="md:peer-data-[variant=inset]:m-2" />
<div className="data-[state=open]:focus:bg-accent" />
// Pseudo-element innermost
<div className="[&>svg]:before:text-red-500" />
<div className="dark:has-[.active]:before:text-red-500" />
// Barreras: los dos órdenes apuntan a elementos distintos, así que los dos quedan
<div className="hover:[&>svg]:w-4" />
<div className="[&>svg]:hover:w-4" />Interacciones con otras reglas
enforce-sort-order: complementaria.enforce-sort-orderordena clases enteras entre sí;consistent-variant-orderordena los prefijos dentro de una clase. Ejecuta las dos.sortTailwindcssde oxfmt: ordena clases enteras y deja la cadena de variants de cada clase tal como está escrita, así que no reemplaza esta regla.enforce-canonical: ortogonal. Canonical normaliza la forma de la utility (m-0,bg-red-500/50), no la cadena de variants.no-unknown-classes: cuando se reordena una variant la clase resultante sigue siendo semánticamente equivalente, así que la detección de clases unknown no ve diferencia.
Cuándo desactivarla
- Orden personalizado de variants que es difícil de expresar como una lista plana (por ejemplo, el orden depende de la utility): desactívala y confía en el review.
- Código generado donde el orden de variants codifica un significado que no quieres que se reescriba.