The has-* Variant

Style a Parent Based on Its Children

The has-* Variant

The has-* variant applies styles to an element when it contains a matching descendant, the inverse of group.

4 min read Level 3/5 #tailwind#variants#has
What you'll learn
  • Use has-[...] to react to descendant elements
  • Combine has-* with group via group-has-*
  • Build a selectable card that restyles when its input is checked

The has-* variant maps to the native CSS :has() selector. It styles an element based on what it contains — the opposite direction from group.

Reacting to Children

Pass a selector inside the brackets. The element is styled only when a matching descendant exists:

<figure class="p-4 has-[img]:p-0 has-[figcaption]:pb-3">
  <img src="photo.jpg" alt="">
</figure>

Here the padding collapses when the figure contains an image. has-[...] accepts any selector, including state selectors like has-[:focus] and has-[:checked].

The Selectable Card Pattern

The classic use is a card that highlights itself when the radio or checkbox inside it is selected:

<label class="block cursor-pointer rounded-lg border p-4
              has-[:checked]:border-blue-500
              has-[:checked]:bg-blue-50
              has-[:checked]:ring-2 has-[:checked]:ring-blue-500">
  <input type="radio" name="plan" class="sr-only">
  <span class="font-medium">Pro plan</span>
</label>

No JavaScript tracks the selection — the label restyles itself purely because it :has() a checked input.

Combining with group

group-has-* lets a descendant react when some other part of the group contains a match:

<article class="group rounded-xl border p-6">
  <a href="#">Linked content</a>
  <footer class="group-has-[a]:underline text-sm text-gray-500">
    Has a link
  </footer>
</article>

This composability — has-*, group-has-*, and arbitrary selectors — replaces a surprising amount of state-tracking script with declarative CSS.

Data & ARIA Attribute Variants →