Tailwind CSS・Reacting to state and screen width

Reacting to state (hover: and focus:)

Write hover:bg-blue-600 and it applies on hover. The exact same mechanism as md:, applied to pseudo-classes. Covers the button set, focus styling, and group-hover, with runnable examples.

The “add a prefix” syntax from the last lesson works for state, not just screen width. The mechanism is identical, so the only new thing is the prefix names.

<button class="bg-orange-500 hover:bg-orange-600">
  Send
</button>

hover:bg-orange-600 means “set the background to orange-600 when the pointer is over it.” In plain CSS:

button {
  background-color: #f97316;
}
button:hover {
  background-color: #ea580c;
}

A CSS pseudo-class, turned straight into a prefix.

The prefixes you’ll use

PrefixPlain CSSWhen it applies
hover::hoverPointer is over it
focus::focusIt has focus
focus-visible::focus-visibleFocused via keyboard
active::activeWhile being pressed
disabled::disabledIt can’t be used
first: / last::first-child / :last-childFirst / last child
odd: / even::nth-child(odd) / (even)Odd / even rows
dark:Dark modeThe device is in dark mode
group-hover:Pointer is over the parentSee below

They stack, too.

<!-- at 768px and up, when hovered -->
<a class="text-slate-600 md:hover:text-orange-500">Link</a>

Conditions accumulate left to right. Read it as “when md:, and hovered.”

The button set

For anything clickable, learning this as one block is the fast path.

<button class="px-6 py-3 bg-orange-500 text-white font-bold rounded-full
               hover:bg-orange-600
               focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2
               active:scale-95
               transition duration-200">
  Send
</button>

Line by line:

  • Line 1—the normal look (spacing, colour, weight, radius)
  • hover:—darken slightly under the pointer
  • focus-visible:—draw a ring when reached by keyboard
  • active:scale-95—shrink slightly while pressed (the “pressed” feel)
  • transition duration-200—smooth the change over 0.2s
CourseAccessibilityWhy focus styling matters, in the accessibility course
hover:bg-orange-600, active:scale-95 and transition, reproduced by hand.

Without transition it feels stiff

With hover: alone the change is instant. Add transition to smooth it.

TailwindPlain CSS
transitionTransitions on the commonly animated properties
transition-colorsColour changes only
duration-200transition-duration: 200ms
ease-outtransition-timing-function: ease-out

Learn transition duration-200 as one block and always add it to clickable things—that alone lifts the feel noticeably.

CourseWeb animationThe thinking behind transitions, in the web animation course

group—react on the parent, style the child

Hovering a whole card should change the title’s colour. In plain CSS:

.card:hover .card__title {
  color: #f97316;
}

In Tailwind, put the marker class group on the parent and group-hover: on the child.

<a href="#" class="group block p-4 bg-white rounded-xl hover:shadow-lg transition">
  <p class="font-bold group-hover:text-orange-500 transition">Shima's page</p>
  <p class="text-sm text-slate-500">Click to open</p>
</a>

group carries no styling of its own—it declares “these children may watch this parent’s state.” Making a whole card clickable is a staple pattern, so this earns its keep.

dark:—supporting dark mode

Styling that only applies in dark mode is also a prefix.

<div class="bg-white text-slate-800 dark:bg-slate-800 dark:text-slate-100 p-4 rounded-xl">
  Readable in either mode
</div>

Base on the light look, then override with dark:—the same instinct as md:, so there’s nothing new to decide.

The thing to watch is keeping declarations in pairs. Write dark:bg-slate-800 and forget the text colour and you get dark text on a dark background. If you change the background, change the text colour—always think of them together.

CSSLet's support dark modeHow dark mode works, in this lesson of the CSS course

Striping rows

odd: and even: are handy in tables and lists.

<ul>
  <li class="p-2 odd:bg-slate-50">Row 1</li>
  <li class="p-2 odd:bg-slate-50">Row 2</li>
  <li class="p-2 odd:bg-slate-50">Row 3</li>
</ul>

Same as plain CSS’s :nth-child(odd): put the identical class on every row and only the odd ones take it. Adding rows changes nothing.

Summary of this lesson

  1. Pseudo-classes are written as prefixes—identical in mechanism to md:
  2. Anything clickable gets the set: hover: + focus-visible: + transition
  3. hover: alone says nothing to keyboard users
  4. group on the parent lets you style children from the parent’s state
  5. dark: overrides a light base—always pair background with text colour
  6. Prefixes attach per class—one can’t cover the rest

That’s the whole way of writing. In the final lesson we turn that feeling you’ve surely had—“plain CSS would be faster here”—into an explicit basis for deciding.

FAQ

How do I write hover styles in Tailwind?
Put hover: in front of the class. hover:bg-orange-600 means "set the background to orange-600 when the pointer is over it." Identical in mechanism to the md: from the last lesson—only the prefix changed.
Is hover alone enough?
No. Someone navigating by keyboard never triggers hover, so pair it with focus-visible:. Anything clickable needs to be legible both by pointer and by keyboard.
How do I make the change animate?
Add the transition class. With hover: alone the change snaps; transition duration-200 makes it smooth.
Can I change a child when the pointer is over the parent?
Yes. Put the class group on the parent and group-hover: on the child. That's how you write the classic "hovering the whole card changes the title colour."