Practice Tailwind CSS
You’ve read the lessons — now prove it. Take the quiz for instant feedback, then work the coding exercises. Try each one yourself before you reveal the solution.
Quick quiz
16 questions- 1
What does the utility class
p-4do in Tailwind CSS? - 2
Which class makes an element a flex container?
- 3
How do you apply a style only on medium screens (768px and above) in Tailwind?
- 4
Which class sets the background color to Tailwind's blue-500?
- 5
What does
justify-betweendo inside a flex container? - 6
Which class applies a style when the user hovers over an element?
- 7
What does
gap-6control inside a flex or grid container? - 8
How do you apply dark-mode styles in Tailwind (with
darkMode: 'class'configured)? - 9
Which class makes an element take up the full width of its container?
- 10
What is an arbitrary value in Tailwind, and which syntax is used?
- 11
Which Tailwind variant applies a style only when the user has NOT requested reduced motion?
- 12
How do you apply gradient text in Tailwind?
- 13
What does the
grouputility enable in Tailwind? - 14
In Tailwind v4, how do you register a custom design token so
bg-brand-500becomes a valid utility? - 15
Which combination of utilities creates a three-column CSS grid that collapses to one column on mobile?
- 16
What is the purpose of the
peerutility in Tailwind?
Coding exercises
8 tasksStyle a Button with Utilities
EasyCreate an HTML <button> that uses only Tailwind utility classes to achieve: blue background (blue-600), white text, medium padding (px-4 py-2), rounded corners (rounded-lg), and a darker blue on hover (hover:bg-blue-700). No custom CSS allowed.
<button class="">
Click me
</button>💡 Show hint
Combine bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 in the class attribute.
✅ Show solution
<button class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400">
Click me
</button>Horizontal Navigation Bar with Flexbox
EasyBuild a <nav> element that:
- Uses flexbox to lay out its children horizontally
- Spaces the links evenly using justify-between
- Has a gray background (bg-gray-800), white text, and p-4 padding
- Contains three <a> links: Home, About, Contact
All styling via Tailwind utility classes only.
<nav class="">
<a href="#" class="">Home</a>
<a href="#" class="">About</a>
<a href="#" class="">Contact</a>
</nav>💡 Show hint
Put flex justify-between on the <nav> and text-white hover:text-gray-300 on the <a> tags.
✅ Show solution
<nav class="flex justify-between items-center bg-gray-800 text-white p-4">
<a href="#" class="hover:text-gray-300 transition-colors">Home</a>
<a href="#" class="hover:text-gray-300 transition-colors">About</a>
<a href="#" class="hover:text-gray-300 transition-colors">Contact</a>
</nav>Responsive Card Grid
MediumCreate a <div> grid of three product cards. Requirements:
- 1 column on mobile, 2 columns on md screens, 3 columns on lg screens
- gap-6 between cards
- Each card has: white background, rounded corners (rounded-xl), shadow (shadow-md), and p-6 padding
- Include a card title (<h2>) and description (<p>) inside each card
Use grid and responsive grid-cols-* prefixes.
<div class="">
<!-- card 1 -->
<div class="">
<h2 class="">Card Title</h2>
<p class="">Card description goes here.</p>
</div>
<!-- repeat x2 -->
</div>💡 Show hint
The wrapper needs grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6. Each card gets bg-white rounded-xl shadow-md p-6.
✅ Show solution
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 p-4">
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-2">Card One</h2>
<p class="text-gray-600 text-sm">Description for the first card.</p>
</div>
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-2">Card Two</h2>
<p class="text-gray-600 text-sm">Description for the second card.</p>
</div>
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-semibold text-gray-800 mb-2">Card Three</h2>
<p class="text-gray-600 text-sm">Description for the third card.</p>
</div>
</div>Dark-Mode Aware Profile Card
MediumBuild a profile card that adapts to dark mode (assume darkMode: 'class' is enabled). The card should:
- Have a light gray background in light mode (bg-gray-100) and dark gray in dark mode (dark:bg-gray-800)
- Show an avatar placeholder (<div> styled as a circle with bg-indigo-400)
- Display a name in dark text (text-gray-900) that becomes light (dark:text-white) in dark mode
- Display a role subtitle in muted color (text-gray-500) with a dark-mode variant (dark:text-gray-400)
- Use group hover to subtly scale the card: group-hover:scale-105 on the inner content
Wrap the whole thing in a <div class="group ...">.
<div class="group">
<!-- avatar -->
<!-- name -->
<!-- role -->
</div>💡 Show hint
Give the outer <div> group bg-gray-100 dark:bg-gray-800 rounded-2xl p-6 transition-transform. Inside, add group-hover:scale-105 transition-transform on the content wrapper.
✅ Show solution
<div class="group bg-gray-100 dark:bg-gray-800 rounded-2xl p-6 shadow-lg w-64 cursor-pointer">
<div class="flex flex-col items-center group-hover:scale-105 transition-transform duration-200">
<div class="w-16 h-16 rounded-full bg-indigo-400 mb-4 flex items-center justify-center text-white text-xl font-bold">
JD
</div>
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Jane Doe</h3>
<p class="text-sm text-gray-500 dark:text-gray-400 mt-1">Frontend Developer</p>
</div>
</div>Full-Page Hero Section with Arbitrary Values and Advanced Utilities
HardBuild a full-page hero section. Requirements:
- Full viewport height (h-screen), centered content (flex items-center justify-center)
- Gradient background: from-violet-600 to-indigo-600 using bg-gradient-to-br
- A centered content <div> with max-w-2xl and text-center
- Headline <h1>: large white text, text-5xl on mobile, md:text-7xl on medium+, bold, with tracking-tight
- Subheading <p>: mt-6, text-violet-200, text-lg, md:text-xl
- Two buttons side by side (flex gap-4 mt-10 justify-center): a white primary button and a transparent outlined secondary button using border border-white text-white
- Primary button hover: slightly off-white background using the arbitrary value hover:bg-[rgba(255,255,255,0.9)] and text-violet-700
- Both buttons: px-6 py-3 rounded-full font-semibold transition-all
- A decorative <div> absolutely positioned at the bottom-right using absolute bottom-8 right-8 with an arbitrary size: w-[200px] h-[200px] circle, bg-white/10 (white at 10% opacity), rounded-full blur-3xl
<section class="relative">
<!-- gradient background, centered flex -->
<!-- content div -->
<!-- h1 -->
<!-- p -->
<!-- buttons -->
<!-- decorative blob -->
</section>💡 Show hint
Make <section> relative h-screen flex items-center justify-center bg-gradient-to-br from-violet-600 to-indigo-600. Give the content wrapper max-w-2xl text-center px-4. For the blob use absolute bottom-8 right-8 w-[200px] h-[200px] bg-white/10 rounded-full blur-3xl pointer-events-none.
✅ Show solution
<section class="relative h-screen flex items-center justify-center bg-gradient-to-br from-violet-600 to-indigo-600 overflow-hidden">
<div class="max-w-2xl text-center px-4 z-10">
<h1 class="text-5xl md:text-7xl font-bold text-white tracking-tight leading-tight">
Build Faster,
<span class="text-violet-200">Ship Better</span>
</h1>
<p class="mt-6 text-lg md:text-xl text-violet-200 max-w-lg mx-auto">
The modern toolkit for developers who care about both speed and quality.
</p>
<div class="flex gap-4 mt-10 justify-center flex-wrap">
<button class="px-6 py-3 rounded-full font-semibold bg-white text-violet-700 transition-all hover:bg-[rgba(255,255,255,0.9)] hover:shadow-lg">
Get Started
</button>
<button class="px-6 py-3 rounded-full font-semibold border border-white text-white transition-all hover:bg-white/10">
Learn More
</button>
</div>
</div>
<div class="absolute bottom-8 right-8 w-[200px] h-[200px] bg-white/10 rounded-full blur-3xl pointer-events-none"></div>
<div class="absolute top-12 left-12 w-[150px] h-[150px] bg-white/5 rounded-full blur-2xl pointer-events-none"></div>
</section>Accessible Animated Skeleton Loader
EasyBuild a skeleton loader card that:
- Has a rounded-xl bg-white shadow p-6 card wrapper
- Contains three placeholder lines: a wide one (w-3/4 h-4), a medium one (w-1/2 h-4 mt-3), and a full-width one (w-full h-4 mt-3)
- Each placeholder line is rounded bg-slate-200
- Uses motion-safe:animate-pulse so the pulse animation only runs for users who have not opted out of motion
- The card is max-w-sm mx-auto
<div class="">
<!-- placeholder lines -->
</div>💡 Show hint
Each line needs rounded bg-slate-200 motion-safe:animate-pulse plus its width, height, and margin classes.
✅ Show solution
<div class="max-w-sm mx-auto rounded-xl bg-white shadow p-6">
<div class="h-4 w-3/4 rounded bg-slate-200 motion-safe:animate-pulse"></div>
<div class="mt-3 h-4 w-1/2 rounded bg-slate-200 motion-safe:animate-pulse"></div>
<div class="mt-3 h-4 w-full rounded bg-slate-200 motion-safe:animate-pulse"></div>
</div>Gradient Text Badge and Glow Button
MediumCreate two adjacent components inside a centered flex container:
1. Gradient badge — a <span> that:
- Has rounded-full px-3 py-1 text-sm font-semibold
- Uses bg-gradient-to-r from-pink-500 to-orange-400 as background
- Text is white
2. Glow button — a <button> that:
- Has rounded-full px-5 py-2 font-semibold text-white bg-indigo-600
- On hover: hover:shadow-lg hover:shadow-indigo-500/50
- Uses motion-safe:transition-shadow motion-safe:duration-300 for an accessible shadow transition
Wrap both in a <div class="flex items-center gap-4 p-8">.
<div class="flex items-center gap-4 p-8">
<span class="">New</span>
<button class="">Get Started</button>
</div>💡 Show hint
The badge needs bg-gradient-to-r from-pink-500 to-orange-400 text-white rounded-full px-3 py-1 text-sm font-semibold. The button needs bg-indigo-600 text-white rounded-full px-5 py-2 font-semibold hover:shadow-lg hover:shadow-indigo-500/50 motion-safe:transition-shadow motion-safe:duration-300.
✅ Show solution
<div class="flex items-center gap-4 p-8">
<span class="rounded-full bg-gradient-to-r from-pink-500 to-orange-400 px-3 py-1 text-sm font-semibold text-white">
New
</span>
<button class="rounded-full bg-indigo-600 px-5 py-2 font-semibold text-white hover:shadow-lg hover:shadow-indigo-500/50 motion-safe:transition-shadow motion-safe:duration-300">
Get Started
</button>
</div>Peer-Validated Email Input
HardBuild an email field with live validation feedback using only Tailwind utilities (no JavaScript):
- A <label> above the input reading "Email address" in text-sm font-medium text-slate-700
- An <input type="email"> with class peer plus base styles: mt-1 block w-full rounded-md border border-slate-300 px-3 py-2 text-sm
- On focus: focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500
- When the input value is invalid (browser-native): peer-invalid:border-red-400 peer-invalid:ring-red-300
- A <p> below the input that shows an error message. It should be invisible by default (opacity-0) and become visible when the input is invalid and not empty (peer-invalid:opacity-100). Style it mt-1 text-xs text-red-500 motion-safe:transition-opacity motion-safe:duration-200
Wrap everything in a <div class="max-w-sm mx-auto p-6">.
<div class="max-w-sm mx-auto p-6">
<label class="">Email address</label>
<input type="email" class="peer" placeholder="you@example.com" />
<p class="">Please enter a valid email address.</p>
</div>💡 Show hint
Mark the input with peer. Then on the sibling <p> use opacity-0 peer-invalid:opacity-100 to toggle visibility based on the input's validity state.
✅ Show solution
<div class="max-w-sm mx-auto p-6">
<label class="text-sm font-medium text-slate-700">Email address</label>
<input
type="email"
placeholder="you@example.com"
class="peer mt-1 block w-full rounded-md border border-slate-300 px-3 py-2 text-sm
focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500
peer-invalid:border-red-400"
/>
<p class="mt-1 text-xs text-red-500 opacity-0 peer-invalid:opacity-100
motion-safe:transition-opacity motion-safe:duration-200">
Please enter a valid email address.
</p>
</div>