Tailwind CSS Interactive States: hover/focus/active State Prefixes and Cursor Styles
State Prefix Overview
Tailwind uses state prefixes to apply styles to elements in different states without writing pseudo-class CSS.
| Prefix | CSS Pseudo-class | Description |
|---|---|---|
hover: |
:hover |
Mouse hover |
focus: |
:focus |
Focused |
active: |
:active |
Mouse pressed |
disabled: |
:disabled |
Disabled state |
visited: |
:visited |
Visited link |
first: |
:first-child |
First child element |
last: |
:last-child |
Last child element |
odd: |
:nth-child(odd) |
Odd child element |
even: |
:nth-child(even) |
Even child element |
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>State Prefix Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto space-y-8">
<!-- hover state -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">hover state</h3>
<div class="flex gap-4">
<button class="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-700 transition-colors">
Darken on hover
</button>
<button class="px-6 py-3 bg-white border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 hover:border-gray-400 transition-colors">
Border on hover
</button>
<button class="px-6 py-3 bg-green-500 text-white rounded-lg hover:shadow-lg hover:shadow-green-500/50 transition-all">
Shadow on hover
</button>
</div>
</div>
<!-- focus state -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">focus state</h3>
<div class="space-y-4">
<input type="text" placeholder="Click the input to see focus effect"
class="w-full p-3 border border-gray-300 rounded-lg focus:border-blue-500 focus:ring-2 focus:ring-blue-500/50 focus:outline-none transition-all">
<input type="text" placeholder="Custom focus shadow"
class="w-full p-3 border border-gray-300 rounded-lg focus:shadow-lg focus:shadow-purple-500/30 focus:border-purple-500 focus:outline-none transition-all">
</div>
</div>
<!-- active state -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">active state</h3>
<div class="flex gap-4">
<button class="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 active:bg-blue-800 active:scale-95 transition-all">
Darken and shrink on press
</button>
<button class="px-6 py-3 bg-white border border-gray-300 text-gray-700 rounded-lg hover:bg-gray-50 active:bg-gray-100 active:scale-95 transition-all">
Press effect
</button>
</div>
</div>
<!-- disabled state -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">disabled state</h3>
<div class="flex gap-4">
<button class="px-6 py-3 bg-blue-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed">
Enabled button
</button>
<button disabled class="px-6 py-3 bg-blue-500 text-white rounded-lg disabled:opacity-50 disabled:cursor-not-allowed">
Disabled button
</button>
<input type="text" placeholder="Enabled input"
class="p-3 border border-gray-300 rounded-lg disabled:bg-gray-100 disabled:cursor-not-allowed">
<input type="text" disabled placeholder="Disabled input"
class="p-3 border border-gray-300 rounded-lg disabled:bg-gray-100 disabled:cursor-not-allowed">
</div>
</div>
<!-- visited links -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">visited links</h3>
<div class="flex gap-4">
<a href="#visited1" class="text-blue-600 hover:text-blue-800 visited:text-purple-600">
Turns purple after clicking
</a>
<a href="#visited2" class="text-green-600 hover:text-green-800 visited:text-gray-400">
Turns gray after clicking
</a>
</div>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind The traditional approach requires writing pseudo-class rules like
button:hover { background-color: ... }, while Tailwind uses prefixes likehover:bg-blue-700to declare them directly.
Tip: State prefixes can be combined, such as
hover:focus:ring-2to apply styles when both hovered and focused.
Structural Pseudo-classes (first/last/odd/even)
Structural pseudo-class prefixes are used to select child elements at specific positions.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Structural Pseudo-class Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto space-y-8">
<!-- first/last -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">first/last</h3>
<ul class="space-y-2">
<li class="p-3 bg-gray-50 rounded first:bg-blue-50 first:text-blue-700 last:bg-green-50 last:text-green-700">
First item (first:bg-blue-50)
</li>
<li class="p-3 bg-gray-50 rounded first:bg-blue-50 first:text-blue-700 last:bg-green-50 last:text-green-700">
Second item
</li>
<li class="p-3 bg-gray-50 rounded first:bg-blue-50 first:text-blue-700 last:bg-green-50 last:text-green-700">
Third item
</li>
<li class="p-3 bg-gray-50 rounded first:bg-blue-50 first:text-blue-700 last:bg-green-50 last:text-green-700">
Last item (last:bg-green-50)
</li>
</ul>
</div>
<!-- odd/even -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">odd/even</h3>
<ul class="space-y-0">
<li class="p-3 odd:bg-white even:bg-gray-50 border-b">Row 1 (odd:bg-white)</li>
<li class="p-3 odd:bg-white even:bg-gray-50 border-b">Row 2 (even:bg-gray-50)</li>
<li class="p-3 odd:bg-white even:bg-gray-50 border-b">Row 3 (odd:bg-white)</li>
<li class="p-3 odd:bg-white even:bg-gray-50 border-b">Row 4 (even:bg-gray-50)</li>
<li class="p-3 odd:bg-white even:bg-gray-50 border-b">Row 5 (odd:bg-white)</li>
<li class="p-3 odd:bg-white even:bg-gray-50">Row 6 (even:bg-gray-50)</li>
</ul>
</div>
<!-- Table example -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Table zebra stripes</h3>
<table class="w-full">
<thead>
<tr class="bg-gray-100">
<th class="p-3 text-left">Name</th>
<th class="p-3 text-left">Email</th>
<th class="p-3 text-left">Role</th>
</tr>
</thead>
<tbody>
<tr class="odd:bg-white even:bg-gray-50 hover:bg-blue-50 transition-colors">
<td class="p-3">Alice</td>
<td class="p-3">alice@example.com</td>
<td class="p-3">Admin</td>
</tr>
<tr class="odd:bg-white even:bg-gray-50 hover:bg-blue-50 transition-colors">
<td class="p-3">Bob</td>
<td class="p-3">bob@example.com</td>
<td class="p-3">Editor</td>
</tr>
<tr class="odd:bg-white even:bg-gray-50 hover:bg-blue-50 transition-colors">
<td class="p-3">Charlie</td>
<td class="p-3">charlie@example.com</td>
<td class="p-3">User</td>
</tr>
<tr class="odd:bg-white even:bg-gray-50 hover:bg-blue-50 transition-colors">
<td class="p-3">Diana</td>
<td class="p-3">diana@example.com</td>
<td class="p-3">User</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind The traditional approach requires writing selectors like
li:first-child { ... }ortr:nth-child(even) { ... }, while Tailwind uses prefixes likefirst:bg-blue-50andeven:bg-gray-50to declare them directly.
group-hover and peer
group-hover: and peer are used to handle interactive states between parent-child or sibling elements.
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>group-hover and peer Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto space-y-8">
<!-- group-hover parent-child hover -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">group-hover parent-child hover</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="group bg-gray-50 rounded-lg p-4 cursor-pointer transition-all hover:shadow-lg">
<div class="w-12 h-12 bg-blue-100 rounded-lg flex items-center justify-center mb-3 group-hover:bg-blue-500 transition-colors">
<span class="text-blue-500 group-hover:text-white transition-colors">🎨</span>
</div>
<h4 class="font-semibold group-hover:text-blue-600 transition-colors">Design Tools</h4>
<p class="text-gray-600 text-sm mt-1 group-hover:text-gray-900 transition-colors">Hover over the parent to see the effect</p>
</div>
<div class="group bg-gray-50 rounded-lg p-4 cursor-pointer transition-all hover:shadow-lg">
<div class="w-12 h-12 bg-green-100 rounded-lg flex items-center justify-center mb-3 group-hover:bg-green-500 transition-colors">
<span class="text-green-500 group-hover:text-white transition-colors">⚡</span>
</div>
<h4 class="font-semibold group-hover:text-green-600 transition-colors">Performance</h4>
<p class="text-gray-600 text-sm mt-1 group-hover:text-gray-900 transition-colors">Hover over the parent to see the effect</p>
</div>
<div class="group bg-gray-50 rounded-lg p-4 cursor-pointer transition-all hover:shadow-lg">
<div class="w-12 h-12 bg-purple-100 rounded-lg flex items-center justify-center mb-3 group-hover:bg-purple-500 transition-colors">
<span class="text-purple-500 group-hover:text-white transition-colors">🔒</span>
</div>
<h4 class="font-semibold group-hover:text-purple-600 transition-colors">Security</h4>
<p class="text-gray-600 text-sm mt-1 group-hover:text-gray-900 transition-colors">Hover over the parent to see the effect</p>
</div>
</div>
</div>
<!-- group combined usage -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">group combined usage</h3>
<div class="space-y-4">
<div class="group flex items-center gap-4 p-4 bg-gray-50 rounded-lg hover:bg-blue-50 transition-colors cursor-pointer">
<div class="w-10 h-10 bg-blue-100 rounded-full flex items-center justify-center group-hover:bg-blue-500 transition-colors">
<svg class="w-5 h-5 text-blue-500 group-hover:text-white transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
<div class="flex-1">
<h4 class="font-medium group-hover:text-blue-600 transition-colors">Menu item 1</h4>
<p class="text-sm text-gray-500 group-hover:text-blue-400 transition-colors">Description text</p>
</div>
<svg class="w-5 h-5 text-gray-400 group-hover:text-blue-500 group-hover:translate-x-1 transition-all" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
<div class="group flex items-center gap-4 p-4 bg-gray-50 rounded-lg hover:bg-green-50 transition-colors cursor-pointer">
<div class="w-10 h-10 bg-green-100 rounded-full flex items-center justify-center group-hover:bg-green-500 transition-colors">
<svg class="w-5 h-5 text-green-500 group-hover:text-white transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
<div class="flex-1">
<h4 class="font-medium group-hover:text-green-600 transition-colors">Menu item 2</h4>
<p class="text-sm text-gray-500 group-hover:text-green-400 transition-colors">Description text</p>
</div>
<svg class="w-5 h-5 text-gray-400 group-hover:text-green-500 group-hover:translate-x-1 transition-all" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
</div>
</div>
</div>
<!-- peer sibling elements -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">peer sibling elements</h3>
<div class="space-y-4">
<div>
<input type="email" id="email" placeholder=" "
class="peer w-full p-3 pt-5 border border-gray-300 rounded-lg focus:border-blue-500 focus:ring-2 focus:ring-blue-500/50 focus:outline-none transition-all">
<label for="email"
class="absolute left-3 top-1 text-gray-400 text-sm transition-all peer-placeholder-shown:top-3.5 peer-placeholder-shown:text-base peer-focus:top-1 peer-focus:text-sm peer-focus:text-blue-500">
Email address
</label>
</div>
<div class="relative">
<input type="password" id="password" placeholder=" "
class="peer w-full p-3 pt-5 border border-gray-300 rounded-lg focus:border-purple-500 focus:ring-2 focus:ring-purple-500/50 focus:outline-none transition-all">
<label for="password"
class="absolute left-3 top-1 text-gray-400 text-sm transition-all peer-placeholder-shown:top-3.5 peer-placeholder-shown:text-base peer-focus:top-1 peer-focus:text-sm peer-focus:text-purple-500">
Password
</label>
</div>
<div class="flex items-center gap-3">
<input type="checkbox" id="agree" class="peer sr-only">
<label for="agree"
class="w-5 h-5 border-2 border-gray-300 rounded peer-checked:bg-blue-500 peer-checked:border-blue-500 cursor-pointer transition-colors flex items-center justify-center">
<svg class="w-3 h-3 text-white opacity-0 peer-checked:opacity-100" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="3" d="M5 13l4 4L19 7"></path>
</svg>
</label>
<span class="text-gray-700">I agree to the terms of service</span>
</div>
</div>
</div>
</div>
</body>
</html>
Tip: Add the
groupclass to a parent element, then use thegroup-hover:prefix on child elements. Add thepeerclass to a preceding sibling element, then use prefixes likepeer-focus:on subsequent sibling elements.
Cursor Styles (cursor-*)
cursor-* classes control the cursor style when the mouse hovers over an element.
| Class | CSS Value | Description |
|---|---|---|
cursor-auto |
cursor: auto |
Auto (default) |
cursor-default |
cursor: default |
Default arrow |
cursor-pointer |
cursor: pointer |
Hand pointer |
cursor-wait |
cursor: wait |
Wait |
cursor-text |
cursor: text |
Text selection |
cursor-move |
cursor: move |
Move |
cursor-not-allowed |
cursor: not-allowed |
Not allowed |
cursor-grab |
cursor: grab |
Grab |
cursor-grabbing |
cursor: grabbing |
Grabbing |
cursor-crosshair |
cursor: crosshair |
Crosshair |
cursor-zoom-in |
cursor: zoom-in |
Zoom in |
cursor-zoom-out |
cursor: zoom-out |
Zoom out |
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cursor Styles Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Cursor Styles</h3>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-auto">
<div class="text-2xl mb-2">👆</div>
<div class="text-sm">cursor-auto</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-default">
<div class="text-2xl mb-2">👆</div>
<div class="text-sm">cursor-default</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-pointer">
<div class="text-2xl mb-2">👆</div>
<div class="text-sm">cursor-pointer</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-wait">
<div class="text-2xl mb-2">⏳</div>
<div class="text-sm">cursor-wait</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-text">
<div class="text-2xl mb-2">📝</div>
<div class="text-sm">cursor-text</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-move">
<div class="text-2xl mb-2">✋</div>
<div class="text-sm">cursor-move</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-not-allowed">
<div class="text-2xl mb-2">🚫</div>
<div class="text-sm">cursor-not-allowed</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-grab">
<div class="text-2xl mb-2">✊</div>
<div class="text-sm">cursor-grab</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-grabbing">
<div class="text-2xl mb-2">✊</div>
<div class="text-sm">cursor-grabbing</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-crosshair">
<div class="text-2xl mb-2">➕</div>
<div class="text-sm">cursor-crosshair</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-zoom-in">
<div class="text-2xl mb-2">🔍</div>
<div class="text-sm">cursor-zoom-in</div>
</div>
<div class="p-4 bg-gray-50 rounded-lg text-center cursor-zoom-out">
<div class="text-2xl mb-2">🔍</div>
<div class="text-sm">cursor-zoom-out</div>
</div>
</div>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind The traditional approach requires writing CSS properties like
cursor: pointer, while Tailwind uses class names likecursor-pointerto declare them directly.
Selection Control (select-*)
select-* classes control whether users can select text.
| Class | CSS Value | Description |
|---|---|---|
select-none |
user-select: none |
Not selectable |
select-text |
user-select: text |
Selectable (default) |
select-all |
user-select: all |
Click to select all |
select-auto |
user-select: auto |
Auto |
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Selection Control Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto space-y-8">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Selection Control</h3>
<div class="space-y-4">
<div class="p-4 bg-gray-50 rounded-lg">
<p class="text-sm text-gray-500 mb-2">select-none: Not selectable</p>
<p class="select-none">This text cannot be selected, suitable for buttons, labels, and other interactive elements.</p>
</div>
<div class="p-4 bg-gray-50 rounded-lg">
<p class="text-sm text-gray-500 mb-2">select-text: Selectable (default)</p>
<p class="select-text">This text can be selected, suitable for body content.</p>
</div>
<div class="p-4 bg-gray-50 rounded-lg">
<p class="text-sm text-gray-500 mb-2">select-all: Click to select all</p>
<p class="select-all bg-blue-50 p-2 rounded font-mono">const apiKey = "abc123";</p>
</div>
</div>
</div>
<!-- Practical application -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Practical Application</h3>
<div class="space-y-4">
<!-- Code block -->
<div class="bg-gray-900 text-green-400 p-4 rounded-lg font-mono text-sm select-all">
npm install tailwindcss
</div>
<!-- Button text not selectable -->
<div class="flex gap-4">
<button class="px-6 py-3 bg-blue-500 text-white rounded-lg select-none cursor-pointer hover:bg-blue-600">
Button text not selectable
</button>
<button class="px-6 py-3 bg-green-500 text-white rounded-lg select-none cursor-pointer hover:bg-green-600">
Confirm Submit
</button>
</div>
</div>
</div>
</div>
</body>
</html>
Tip:
select-noneis commonly used for buttons, labels, and other elements where text selection is unnecessary.select-allis commonly used for code blocks and command lines where one-click copying is desired.
Resize Control (resize-*)
resize-* classes control whether an element can be resized.
| Class | CSS Value | Description |
|---|---|---|
resize-none |
resize: none |
Not resizable |
resize-y |
resize: vertical |
Vertical resize only |
resize-x |
resize: horizontal |
Horizontal resize only |
resize |
resize: both |
Resizable |
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Resize Control Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto space-y-8">
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Resize Control</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<p class="text-sm text-gray-500 mb-2">resize-none: Not resizable</p>
<textarea class="w-full p-3 border border-gray-300 rounded-lg resize-none h-24 focus:outline-none focus:border-blue-500"
placeholder="Non-resizable textarea"></textarea>
</div>
<div>
<p class="text-sm text-gray-500 mb-2">resize-y: Vertical resize only</p>
<textarea class="w-full p-3 border border-gray-300 rounded-lg resize-y h-24 focus:outline-none focus:border-blue-500"
placeholder="Vertically resizable textarea"></textarea>
</div>
<div>
<p class="text-sm text-gray-500 mb-2">resize-x: Horizontal resize only</p>
<textarea class="w-full p-3 border border-gray-300 rounded-lg resize-x h-24 focus:outline-none focus:border-blue-500"
placeholder="Horizontally resizable textarea"></textarea>
</div>
<div>
<p class="text-sm text-gray-500 mb-2">resize: Resizable</p>
<textarea class="w-full p-3 border border-gray-300 rounded-lg resize h-24 focus:outline-none focus:border-blue-500"
placeholder="Freely resizable textarea"></textarea>
</div>
</div>
</div>
</div>
</body>
</html>
Traditional CSS vs Tailwind The traditional approach requires writing CSS properties like
resize: vertical, while Tailwind uses class names likeresize-yto declare them directly.
Scroll Behavior (scroll-*)
scroll-* classes control scroll behavior.
| Class | CSS Value | Description |
|---|---|---|
scroll-auto |
scroll-behavior: auto |
Auto (default) |
scroll-smooth |
scroll-behavior: smooth |
Smooth scrolling |
snap-start |
scroll-snap-align: start |
Snap to start |
snap-center |
scroll-snap-align: center |
Snap to center |
snap-end |
scroll-snap-align: end |
Snap to end |
snap-none |
scroll-snap-type: none |
No snapping |
snap-x |
scroll-snap-type: x mandatory |
Horizontal snapping |
snap-y |
scroll-snap-type: y mandatory |
Vertical snapping |
Example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scroll Behavior Demo</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
<div class="max-w-4xl mx-auto space-y-8">
<!-- Smooth scrolling -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Smooth Scrolling</h3>
<div class="flex gap-4 mb-4">
<a href="#section1" class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600">Jump to Section 1</a>
<a href="#section2" class="px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600">Jump to Section 2</a>
<a href="#section3" class="px-4 py-2 bg-purple-500 text-white rounded-lg hover:bg-purple-600">Jump to Section 3</a>
</div>
<div class="h-48 overflow-y-auto scroll-smooth border rounded-lg">
<div id="section1" class="p-4 bg-blue-50 h-48 flex items-center justify-center">
<h4 class="text-xl font-bold text-blue-700">Section 1</h4>
</div>
<div id="section2" class="p-4 bg-green-50 h-48 flex items-center justify-center">
<h4 class="text-xl font-bold text-green-700">Section 2</h4>
</div>
<div id="section3" class="p-4 bg-purple-50 h-48 flex items-center justify-center">
<h4 class="text-xl font-bold text-purple-700">Section 3</h4>
</div>
</div>
</div>
<!-- Scroll snapping -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Scroll Snapping</h3>
<div class="flex overflow-x-auto snap-x snap-mandatory gap-4 pb-4">
<div class="snap-center flex-shrink-0 w-64 h-40 bg-blue-100 rounded-lg flex items-center justify-center">
<span class="text-blue-700 font-semibold">Card 1</span>
</div>
<div class="snap-center flex-shrink-0 w-64 h-40 bg-green-100 rounded-lg flex items-center justify-center">
<span class="text-green-700 font-semibold">Card 2</span>
</div>
<div class="snap-center flex-shrink-0 w-64 h-40 bg-purple-100 rounded-lg flex items-center justify-center">
<span class="text-purple-700 font-semibold">Card 3</span>
</div>
<div class="snap-center flex-shrink-0 w-64 h-40 bg-orange-100 rounded-lg flex items-center justify-center">
<span class="text-orange-700 font-semibold">Card 4</span>
</div>
<div class="snap-center flex-shrink-0 w-64 h-40 bg-red-100 rounded-lg flex items-center justify-center">
<span class="text-red-700 font-semibold">Card 5</span>
</div>
</div>
</div>
<!-- Hidden scrollbar -->
<div class="bg-white rounded-lg shadow p-6">
<h3 class="font-semibold mb-4">Hidden Scrollbar</h3>
<div class="flex overflow-x-auto scrollbar-hide gap-4 pb-4">
<div class="flex-shrink-0 w-48 h-32 bg-gradient-to-br from-blue-400 to-blue-600 rounded-lg flex items-center justify-center text-white">
Hidden scrollbar
</div>
<div class="flex-shrink-0 w-48 h-32 bg-gradient-to-br from-green-400 to-green-600 rounded-lg flex items-center justify-center text-white">
Using scrollbar-hide
</div>
<div class="flex-shrink-0 w-48 h-32 bg-gradient-to-br from-purple-400 to-purple-600 rounded-lg flex items-center justify-center text-white">
Horizontally scrollable
</div>
<div class="flex-shrink-0 w-48 h-32 bg-gradient-to-br from-orange-400 to-orange-600 rounded-lg flex items-center justify-center text-white">
Keep scrolling
</div>
</div>
</div>
</div>
</body>
</html>
Tip: Adding
scroll-smoothto the<html>element enables smooth scrolling for the entire page. Combiningsnap-x snap-mandatorywithsnap-centercreates a carousel effect.
❓ FAQ
hover: is the element's own hover state. group-hover: applies styles to child elements when the parent element (with the group class) is hovered. It's ideal for coordinated hover effects between parent and child elements.peer class to an element, then use prefixes like peer-focus: and peer-valid: to style subsequent sibling elements. Commonly used for floating labels and form validation.disabled: prefix is used with the actual disabled attribute. Tailwind generates the .disabled\:opacity-50:disabled selector, so the element must have the disabled attribute for it to take effect.snap-x snap-mandatory (horizontal) or snap-y snap-mandatory (vertical) to the scroll container, and add snap-center or snap-start to child elements.📖 Summary
hover:,focus:,active:,disabled:and other state prefixes control element interactive statesfirst:,last:,odd:,even:and other structural pseudo-classes select specific child elementsgroupandgroup-hover:handle coordinated hover effects between parent and child elementspeerandpeer-focus:handle coordinated states between sibling elementscursor-*controls cursor styles,select-*controls text selectionresize-*controls element resizing,scroll-*controls scroll behavior
📝 Exercises
-
⭐ Create a button component using
hover:,focus:,active:, anddisabled:state prefixes to implement full interactive state styling -
⭐⭐ Create a navigation menu using
groupandgroup-hover:to implement coordinated hover changes for icons, text, and arrows -
⭐⭐⭐ Create a form using
peerandpeer-focus:to implement floating label effects, combined withfocus:andinvalid:states for form validation styling



