Capítulo 11 de 29
Every interactive/structural/conditional state in Tailwind is a class prefix ("variant") stacked directly on a utility — hover:bg-sky-700, dark:lg:has-checked:bg-indigo-50 — covering pseudo-classes, pseudo-elements, media/feature queries, attribute selectors, and parent/sibling/descendant relationships, all composable in one system instead of scattered across media queries, :hover blocks, and JS state.
hover:, focus:, active:, plus visited:, focus-within:, focus-visible:.first:, last:, only:, odd:, even:, first-of-type:, last-of-type:, only-of-type:, empty:. nth-<n>:/nth-last-<n>:/nth-of-type-<n>:/nth-last-of-type-<n>: take a number directly (nth-3:underline) or an arbitrary expression (nth-[2n+1_of_li]).required:, invalid:, valid:, disabled:, enabled:, read-only:, indeterminate:, checked:, default:, optional:, placeholder-shown:, autofill:, in-range:, out-of-range:. Styling these as variants (instead of branching class strings in JS per form state) keeps one class list that works regardless of the input's current state.:has() → has-*: styles an element based on its descendants — has-checked:bg-indigo-50 on a <label> wrapping a radio input styles the label once that input is checked. Combine with a pseudo-class (has-[:focus]) or an element selector (has-[img], has-[a]) arbitrarily.:not() → not-*: styles when a condition is false — e.g. hover:not-focus:bg-indigo-700 applies hover styles only while not focused. Combines with media/feature variants too (not-supports-[display:grid]:flex).group + group-*: mark an ancestor group (name it group/{name} when nested groups need disambiguation, target with group-hover/{name}:), then style any descendant with group-hover:, group-focus:, group-has-checked:, group-has-[a]:, etc.peer + peer-*: mark a sibling peer (nameable the same way, peer/{name}), then style a later sibling with peer-checked:, peer-has-checked:, etc. — CSS's ~ general sibling combinator only looks forward, so the peer element must come before the styled element in markup.before:/after: — require setting content-[''] (or a real string) to render; commonly paired with utilities for size/position/color to draw decorative marks.placeholder: — styles ::placeholder text.file: — styles the button part of <input type="file">.marker: — styles list bullets/numbers (::marker).selection: — styles user text-selection highlight color.first-line:/first-letter: — styles ::first-line/::first-letter.backdrop: — styles the ::backdrop behind a native <dialog>/fullscreen element.sm:…2xl:) and container queries (@sm:…) are variants too — see the Responsive Design and Container Queries chapters.dark: — prefers-color-scheme: dark (overridable, see Dark Mode chapter).motion-reduce:/motion-safe: — prefers-reduced-motion.contrast-more:/contrast-less: — prefers-contrast.forced-colors: — Windows High Contrast / forced-colors mode; pairs with forced-color-adjust-* utilities to opt specific elements in/out.inverted-colors: — OS-level color inversion.pointer-fine:/pointer-coarse:/pointer-none: and any-pointer-* variants — primary vs. any available pointer precision (mouse vs. touch).portrait:/landscape: — device/viewport orientation.noscript: — (scripting: none), i.e. JS disabled.print: — print media.supports-[...]: — arbitrary @supports feature-query variant, e.g. supports-[display:grid]:grid.starting: — @starting-style, for entry-transition starting values (animating an element in on first paint/mount, no JS needed).aria-checked:, aria-disabled:, aria-expanded:, aria-hidden:, aria-pressed:, aria-selected:, and more — target aria-* attributes set by JS UI libraries directly, plus aria-[<name>=<value>] for arbitrary ARIA attribute/value pairs.data-[<name>]:/data-[<name>=<value>]: — styles based on a custom data-* attribute (common with headless UI libraries that expose state via data-state, data-open, etc.).rtl:/ltr: — style differently based on text direction, for logical/directional overrides beyond what the ps-*/pe-*/start-*/end-* logical-property utilities already handle automatically.open: — targets the [open] attribute on <details>, <dialog>, and the Popover API's open state.inert: — targets elements with the inert attribute (interaction-disabled, kept in the accessibility tree as non-interactive) — pair with utilities to visually de-emphasize inert content (e.g. dim it) to match its non-interactive state.*: — styles direct children (*: prefix applied to the parent, e.g. *:rounded-full rounds every direct child). Intentionally shallow — does not reach grandchildren.**: — styles all descendants, not just direct children (use sparingly — broad selectors are easy to fight later).[&:nth-child(-n+3)]:hover:underline-style square-bracket selector for a one-off condition with no built-in variant (see Adding Custom Styles chapter for the full arbitrary-variant syntax).@custom-variant in CSS (see Adding Custom Styles / Functions and Directives chapters) — the CSS-side counterpart for anything used repeatedly enough to deserve a name.
<div class="dark:lg:group-has-checked:hover:bg-indigo-900">...</div>
<label class="peer ...">
<input type="checkbox" />
</label>
<svg class="peer-has-checked:hidden ...">...</svg>
peer-*/group-* both require the marked element (peer/group) to be an ancestor (group) or an earlier sibling (peer) of the styled element.| Relationship | Mark this element | Style with |
|---|---|---|
| Descendant based on ancestor state | ancestor gets group (or group/{name}) | descendant: group-*: (or group-*/{name}:) |
| Element based on a later/earlier sibling | sibling gets peer (or peer/{name}) | a later sibling: peer-*: (or peer-*/{name}:) |
| Element based on its own descendants | — | has-*:, e.g. has-checked:, has-[img]: |
| Direct children only | — | *: on the parent |
| All descendants | — | **: on the ancestor |
peer-* requires the peer element to appear before the styled element in the DOM (sibling combinators only look forward) — group-* has no such ordering constraint since it targets any descendant.has-* styles an element by its own descendants' state/content; group-has-*/peer-has-* extend that same descendant-check to an ancestor's or sibling's descendants.data-[...]:/aria-[...]: variants before writing custom JS-driven class toggling when a headless UI library already exposes state via attributes.@starting-style (starting:) enables enter transitions without JS — check browser support before relying on it as the only entry animation.dark: is a variant like any other, overridable via @custom-variant.[&:...]:) and @custom-variant registration are documented there in full.