Tailwind CSS Tutorial · Interactivity and States · Lesson 16 of 27
Group, Peer and Has
Styling an element based on its parent's or sibling's state with group-*, peer-* and has-* variants.
group: react to a parent
Mark the parent with group; children use group-hover:, group-focus: and so on:
<a href="#" class="group m-6 block max-w-xs rounded-xl border p-5 hover:border-sky-500 hover:bg-sky-500">
<p class="font-semibold text-gray-900 group-hover:text-white">New project</p>
<p class="text-sm text-gray-500 group-hover:text-sky-100">Hover the whole card: the text changes too</p>
<span class="mt-3 inline-block text-sky-600 transition group-hover:translate-x-1 group-hover:text-white">Create →</span>
</a>
peer: react to a previous sibling
Mark an element with peer; later siblings use peer-checked:, peer-focus:, peer-invalid::
<label class="m-6 flex items-center gap-3">
<input type="checkbox" class="peer size-5 accent-emerald-600">
<span class="text-gray-500 peer-checked:font-semibold peer-checked:text-emerald-700 peer-checked:line-through">Water the plants</span>
</label>
has: react to children
has-checked: (or has-[input:checked]:) styles an element when it contains a matching child. No JavaScript
needed:
<div class="grid gap-3 p-6 sm:grid-cols-2">
<label class="rounded-xl border-2 border-gray-200 p-4 has-checked:border-violet-500 has-checked:bg-violet-50">
<input type="radio" name="plan" class="sr-only" checked>
<p class="font-semibold">Starter</p><p class="text-sm text-gray-500">Free</p>
</label>
<label class="rounded-xl border-2 border-gray-200 p-4 has-checked:border-violet-500 has-checked:bg-violet-50">
<input type="radio" name="plan" class="sr-only">
<p class="font-semibold">Pro</p><p class="text-sm text-gray-500">$12 / month</p>
</label>
</div>
Test yourself
A label should change colour when the checkbox before it is checked. Which variant?
peer-checked:group-checked:checked:has-checked:
Show answer
Answer: peer-checked:
peer-* targets later siblings of an element marked with the peer class.