State Variants in Tailwind
Tailwind provides modifiers for styling elements based on their state. These modifiers can be combined with any utility class.
Hover State
<!-- Basic hover -->
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded">
Hover me
</button>
<!-- Hover with multiple changes -->
<div class="bg-white hover:bg-gray-50 hover:shadow-lg transition-all p-4 rounded">
Hover for effects
</div>
<!-- Hover text color -->
<a href="#" class="text-gray-600 hover:text-blue-600">
Hover link
</a>
Focus State
<!-- Focus ring -->
<input
type="text"
class="border border-gray-300 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 rounded px-4 py-2 outline-none"
placeholder="Focus me"
>
<!-- Focus visible (keyboard only) -->
<button class="px-4 py-2 bg-blue-500 text-white rounded focus-visible:ring-2 focus-visible:ring-blue-300 focus-visible:ring-offset-2">
Keyboard focus only
</button>
<!-- Focus within (child focused) -->
<div class="p-4 border focus-within:border-blue-500 focus-within:ring-2 focus-within:ring-blue-200 rounded">
<input type="text" class="outline-none" placeholder="Focus changes parent">
</div>
Active State
<button class="bg-blue-500 hover:bg-blue-600 active:bg-blue-700 active:scale-95 transition-all text-white px-4 py-2 rounded">
Click and hold
</button>
Disabled State
<button
disabled
class="bg-blue-500 text-white px-4 py-2 rounded disabled:bg-gray-300 disabled:cursor-not-allowed disabled:opacity-50"
>
Disabled Button
</button>
<input
disabled
class="border rounded px-4 py-2 disabled:bg-gray-100 disabled:text-gray-400"
value="Disabled input"
>
Group Hover
Style child elements based on parent hover state:
<div class="group p-4 bg-white hover:bg-blue-500 rounded transition-colors">
<h3 class="font-bold text-gray-900 group-hover:text-white">
Card Title
</h3>
<p class="text-gray-600 group-hover:text-blue-100">
Card description changes on parent hover
</p>
<span class="text-blue-500 group-hover:text-white group-hover:translate-x-2 inline-block transition-all">
Learn more →
</span>
</div>
Peer Modifier
Style an element based on sibling state:
<div>
<input type="checkbox" id="toggle" class="peer sr-only">
<label for="toggle" class="cursor-pointer">Toggle</label>
<div class="hidden peer-checked:block mt-2 p-4 bg-green-100 rounded">
This appears when checkbox is checked
</div>
</div>
<!-- Form validation styling -->
<div>
<input
type="email"
class="peer border rounded px-4 py-2 invalid:border-red-500"
placeholder="Enter email"
required
>
<p class="hidden peer-invalid:block text-red-500 text-sm mt-1">
Please enter a valid email
</p>
</div>
First, Last, Odd, Even
<ul class="divide-y">
<li class="py-2 first:pt-0 last:pb-0">Item 1</li>
<li class="py-2 first:pt-0 last:pb-0">Item 2</li>
<li class="py-2 first:pt-0 last:pb-0">Item 3</li>
</ul>
<!-- Zebra striping -->
<table>
<tbody>
<tr class="odd:bg-gray-50 even:bg-white"><td>Row 1</td></tr>
<tr class="odd:bg-gray-50 even:bg-white"><td>Row 2</td></tr>
<tr class="odd:bg-gray-50 even:bg-white"><td>Row 3</td></tr>
</tbody>
</table>
Form States
<!-- Required field -->
<input
type="text"
required
class="border rounded px-4 py-2 required:border-red-500"
>
<!-- Valid/Invalid -->
<input
type="email"
class="border rounded px-4 py-2 valid:border-green-500 invalid:border-red-500"
>
<!-- Placeholder shown -->
<input
type="text"
placeholder="Enter name"
class="border rounded px-4 py-2 placeholder-shown:border-gray-300"
>
<!-- Read only -->
<input
readonly
value="Read only"
class="border rounded px-4 py-2 read-only:bg-gray-100"
>
Combining States
<!-- Responsive + hover -->
<button class="bg-blue-500 md:hover:bg-blue-600 lg:hover:bg-blue-700">
Responsive hover
</button>
<!-- Dark mode + hover -->
<button class="bg-white hover:bg-gray-100 dark:bg-gray-800 dark:hover:bg-gray-700">
Dark mode aware
</button>
<!-- Group + focus -->
<div class="group">
<input class="peer" type="text">
<span class="group-hover:text-blue-500 peer-focus:text-green-500">
Label
</span>
</div>
Interactive Button Example
<button class="
px-6 py-3
bg-gradient-to-r from-blue-500 to-purple-500
hover:from-blue-600 hover:to-purple-600
active:from-blue-700 active:to-purple-700
focus:ring-4 focus:ring-blue-300
disabled:from-gray-400 disabled:to-gray-400 disabled:cursor-not-allowed
text-white font-semibold rounded-lg
transform hover:scale-105 active:scale-95
transition-all duration-200
shadow-lg hover:shadow-xl
">
Interactive Button
</button>