Tailwind Group and Peer

Hover and focus classes normally affect the element you touch. Real designs often need a different result: pointing at a card should change the title inside it, or checking a box should change the label beside it. Group and peer variants solve both cases without any JavaScript.

The Group Variant

Add the group class to a parent element. Children can then react to the state of that parent with variants such as group-hover: and group-focus:. Think of a parent calling a family meeting: when the parent speaks, every child responds.

<a href="#" class="group block rounded-lg border p-4">
  <h4 class="font-bold group-hover:text-sky-600">Card Title</h4>
  <span class="opacity-0 group-hover:opacity-100">→</span>
</a>

Mouse away                  Mouse over the card
┌──────────────────┐        ┌──────────────────┐
│ Card Title       │   →    │ Card Title   →   │
└──────────────────┘        └──────────────────┘
 title black, no arrow       title blue, arrow visible

Pointing anywhere on the card triggers the change, even though the title and arrow never received the mouse themselves.

Named Groups

Nested groups create confusion because every child reacts to the closest group. Give each group a name with a slash and target that name in the variant.

<div class="group/card">
  <div class="group/item">
    <p class="group-hover/card:underline group-hover/item:font-bold">Text</p>
  </div>
</div>

The text underlines when the outer card is hovered and turns bold when the inner item is hovered. Names remove all guesswork.

Group State Variants

Variant               Reacts when the parent group is...
───────────────────────────────────────────────────────
group-hover:          hovered
group-focus:          focused
group-active:         pressed
group-focus-within:   holding a focused child
group-disabled:       disabled
group-has-[...]:      containing a matching element

The Peer Variant

The peer class works sideways. Mark one element as a peer, and its siblings that come after it can react to its state with peer-checked:, peer-focus:, or peer-invalid:. The reaction only travels forward, so the peer must appear earlier in the markup.

Markup order matters

<input class="peer">          ← the peer (first)
<label class="peer-checked:...">  ← reacts (comes after)

Reverse order does NOT work.

Custom Toggle Switch Example

A hidden checkbox drives the whole switch. The track and the knob respond to the checked state.

<label class="relative inline-flex cursor-pointer items-center">
  <input type="checkbox" class="peer sr-only">
  <div class="h-6 w-11 rounded-full bg-gray-300 peer-checked:bg-sky-600"></div>
  <div class="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition peer-checked:translate-x-5"></div>
</label>

Off:  (●      )  gray track
On:   (      ●)  blue track, knob slides right

Screen readers still announce the checkbox because the sr-only class hides it visually while keeping it in the page structure.

Form Validation Message Example

Show an error message only when the typed value fails the browser check. An email field without the required attribute counts as valid while empty, so the message stays hidden on a fresh form.

<input type="email" placeholder="you@example.com" class="peer border p-2">
<p class="hidden text-sm text-red-600 peer-invalid:block">
  Enter a valid email address.
</p>

Empty field          →  no message
you@                 →  message appears
you@example.com      →  message disappears

The message follows the field state in real time. Visitors receive instant feedback without a single line of script.

Group vs Peer Quick Guide

Need                                   Use
──────────────────────────────────────────────
Child reacts to its parent             group
Sibling reacts to an earlier sibling   peer
Several children react together        group
Label reacts to a checkbox             peer

Why Not Use JavaScript

Scripts can toggle classes on hover or click, but each script adds code to maintain, a delay while the page loads, and a chance for bugs. CSS state variants run inside the browser engine, which handles them instantly. The browser tracks details that scripts often forget, such as keyboard focus, touch screens, and disabled controls. Choosing group and peer variants gives faster pages and fewer defects.

Picking the Right Parent

Choose the group parent with care. A group on the whole page means every hover anywhere triggers children everywhere. A group on one card limits the effect to that card. Smaller groups give clearer results.

The same rule applies to peers. Wrap related controls in a small container, then place the peer and its dependent elements next to each other inside it. Long distances between the peer and the reacting element signal that a different structure, such as a parent group, might fit better.

Accessibility Notes

Hover effects help mouse users only. Touch screens and keyboards need an equal path. Pair every group-hover: class with group-focus-within: so a keyboard user who tabs into the card sees the same change. Hidden checkboxes need the sr-only class instead of hidden, because hidden removes the control from the keyboard order completely.

Good Habits

  • Keep group parents small so a hover area stays predictable.
  • Name groups whenever you nest them.
  • Place the peer element before the elements that depend on it.
  • Test keyboard focus along with mouse hover so every visitor gets the same feedback.

These two variants replace many small scripts. State-based styling stays in the markup, and the page remains fast.