CPCODELAB
Practice

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
Score: 0 / 16
0/16 answered
  1. 1

    What does the utility class p-4 do in Tailwind CSS?

  2. 2

    Which class makes an element a flex container?

  3. 3

    How do you apply a style only on medium screens (768px and above) in Tailwind?

  4. 4

    Which class sets the background color to Tailwind's blue-500?

  5. 5

    What does justify-between do inside a flex container?

  6. 6

    Which class applies a style when the user hovers over an element?

  7. 7

    What does gap-6 control inside a flex or grid container?

  8. 8

    How do you apply dark-mode styles in Tailwind (with darkMode: 'class' configured)?

  9. 9

    Which class makes an element take up the full width of its container?

  10. 10

    What is an arbitrary value in Tailwind, and which syntax is used?

  11. 11

    Which Tailwind variant applies a style only when the user has NOT requested reduced motion?

  12. 12

    How do you apply gradient text in Tailwind?

  13. 13

    What does the group utility enable in Tailwind?

  14. 14

    In Tailwind v4, how do you register a custom design token so bg-brand-500 becomes a valid utility?

  15. 15

    Which combination of utilities creates a three-column CSS grid that collapses to one column on mobile?

  16. 16

    What is the purpose of the peer utility in Tailwind?

🛠️

Coding exercises

8 tasks
1

Style a Button with Utilities

Easy

Create 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.

Starter
html
<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
html
<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>
2

Horizontal Navigation Bar with Flexbox

Easy

Build 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.

Starter
html
<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
html
<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>
3

Responsive Card Grid

Medium

Create 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.

Starter
html
<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
html
<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>
4

Dark-Mode Aware Profile Card

Medium

Build 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 ...">.

Starter
html
<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
html
<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>
5

Full-Page Hero Section with Arbitrary Values and Advanced Utilities

Hard

Build 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

Starter
html
<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
html
<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>
6

Accessible Animated Skeleton Loader

Easy

Build 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

Starter
html
<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
html
<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>
7

Gradient Text Badge and Glow Button

Medium

Create 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">.

Starter
html
<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
html
<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>
8

Peer-Validated Email Input

Hard

Build 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">.

Starter
html
<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
html
<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>