Pseudoclases
:hover, :focus, y :active
Para aplicar estilos en estos estados hay que utilizar lo que en Tailwind se llaman variantes (variants). Simplemente pon el nombre del estado seguido de 2 puntos ':' y el estilo que se aplicará en este caso.
<button class="border border-blue-200 px-2 py-1 text-blue-900 rounded-lg hover:bg-blue-200 active:shadow-md active:shadow-blue-500/40 active:text-blue-100 focus:bg-blue-500 focus:text-white">Hola</button>

:first, :last, :odd, y :even
Se utilizan igual que las anteriores, e incluso se pueden combinar (Ejemplo: first:hover:text-blue-500). Este tipo de clases solo tiene sentido usarlas cuando las combinamos con algún sistema de generación de contenido dinámico ya sea en el back-end o en el front con algún framework.
@for(item in items; track $index) {
<li class="even:bg-gray-50">item</li>
}Validaciones de campos
También se pueden gestionar de manera similar estados de validación de formularios o también cuando se deshabilita algún campo o botón (disabled).
<form id="task-form" class="space-y-4">
<div>
<label for="title" class="block text-sm font-medium text-gray-700">Título</label>
<input type="text" id="title" name="title"
class="user-invalid:border-red-500 user-invalid:outline-red-500 user-valid:border-green-500 user-valid:outline-green-500 mt-1 block w-full px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm placeholder-gray-400 outline-indigo-500 sm:text-sm"
required minlength="5" pattern="[a-zA-Z0-9\s]+">
</div>
<button type="submit" class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Añadir Tarea</button>
</form>
Estilo en base a sus descendientes (has)
Con la variante has-*: podemos gestionar el estilo de un elemento en base al estado de alguno de sus descendientes. Por ejemplo, has-checked, has-required, has-disabled, etc.
<label class="px-2 py-1 border border-transparent has-checked:border-rose-600 has-checked:bg-rose-50 text-rose-600 flex items-center gap-2 rounded-md">
<input type="checkbox" class="accent-rose-600 me-2 size-4">
Check me
</label>
Negación de estado (not)
Estilo cuando no tiene un estado (not-*). Se puede combinar con todo lo anterior.
<ul class="*:py-1 *:px-2">
<li class="not-first:border-t not-first:border-gray-300">Item 1</li>
<li class="not-first:border-t not-first:border-gray-300">Item 2</li>
<li class="not-first:border-t not-first:border-gray-300">Item 3</li>
<li class="not-first:border-t not-first:border-gray-300">Item 4</li>
</ul>
Estilo basado en ascendiente (group)
Si asignamos la clase group a un elemento, podemos gestionar estilos en sus descendientes en base al estado de este elemento utilizando variantes como group-hover, group-active, etc.
<ul class="*:py-1 *:px-2 group">
<li class="group-hover:text-blue-600 not-first:border-t not-first:border-gray-300">Item 1</li>
<li class="group-hover:text-blue-600 not-first:border-t not-first:border-gray-300">Item 2</li>
<li class="group-hover:text-blue-600 not-first:border-t not-first:border-gray-300">Item 3</li>
<li class="group-hover:text-blue-600 not-first:border-t not-first:border-gray-300">Item 4</li>
</ul>
Si tenemos varios group anidados, debemos asignarle un alias diferente a cada uno. Esto se hace asignando la clase group/alias al elemento y usando esto en los elementos descendientes.
Estilo basado en hermano anterior (peer)
De una forma similar a la anterior, podemos marcar un elemento con la clase peer y aplicar a hermanos posteriores estilos basandonos en el estado de ese elemento anterior (peer-hover, peer-focus, etc...). Por ejemplo, podríamos crear un label flotante sin necesidad de JavaScript:
<div class="relative">
<input id="nombre" type="text" class="peer px-2 pb-1 pt-5 border border-gray-400 rounded-lg" placeholder="">
<label for="nombre" class="absolute left-2 top-1 text-sm text-gray-500 peer-focus:text-sm peer-focus:top-1 peer-placeholder-shown:text-lg peer-placeholder-shown:top-5 transition-all duration-300">Enter name</label>
</div>