Stacking Variants: Responsive + Dark + State

Compose multiple conditions on one utility and keep the result readable.

Variants stack. Chain them with colons and the utility applies only when every condition is true, read left to right.

md:dark:hover:bg-slate-700

That means: from the md breakpoint up, in dark mode, on hover — use this background. Any one condition false, the utility sits out.

Dark mode in v4

By default dark: follows the operating system via prefers-color-scheme. Want a manual toggle instead? Register a class-based variant once in CSS:

@custom-variant dark (&:where(.dark, .dark *));

Now adding class="dark" to any ancestor switches every dark: utility beneath it.

The powerful newer variants

  • has-[...]: — style a parent based on a descendant (has-[:checked]:bg-cyan-50).
  • not-* — negate a variant (not-first:border-t).
  • *: — target direct children (*:rounded-lg).

Keep it scannable

Stacking order does not change specificity, but it changes how fast a teammate parses the class. Pick one order — breakpoint, then theme, then state — and hold to it everywhere.

Example

Try it yourself
Loading editor…
Press Run to see the result.

When to use it

  • A developer applies dark:md:text-white to show white text only on medium screens in dark mode without writing any media-query CSS.
  • A button uses group-hover:focus:ring-2 so the focus ring only appears when the button is focused and its parent card is hovered.
  • A complex form input combines hover:dark:border-indigo-400 so the border changes color only in dark mode on hover.

More examples

Dark mode + responsive stack

dark:md:text-xl applies a larger font only at medium breakpoints when in dark mode, while each prefix condition is independent for other combinations.

Example Β· html
<p class="text-gray-700
          dark:text-gray-300
          md:text-lg
          dark:md:text-xl">
  Text adapts to mode and breakpoint independently.
</p>

State + responsive stack

Breakpoint prefixes before hover: change the hover color at each viewport size, showing how state variants compose with responsive prefixes.

Example Β· html
<button
  class="bg-gray-100 px-4 py-2 rounded
         hover:bg-gray-200
         md:hover:bg-indigo-100
         lg:hover:bg-indigo-200 lg:hover:text-indigo-800"
>
  Multi-context hover
</button>

Triple variant: responsive + dark + state

md:dark:focus:ring-indigo-500 stacks three conditions β€” breakpoint, color scheme, and input state β€” into a single utility for fine-grained control.

Example Β· html
<input
  type="text"
  class="border rounded px-3 py-2 w-full
         focus:ring-2 focus:ring-blue-500
         dark:focus:ring-indigo-400
         md:dark:focus:ring-offset-2 md:dark:focus:ring-indigo-500"
/>

Discussion

  • Be the first to comment on this lesson.
Stacking Variants: Responsive + Dark + State β€” Tailwind CSS | SoundsCode