Skip to main content
Tailwind CSS Mastery·Lesson 1 of 5

Utility-First Workflow

Tailwind CSS takes a radically different approach to styling. Instead of writing custom CSS classes like .card-title or .btn-primary, you compose designs directly in your markup using small, single-purpose utility classes.

Why Utility-First?

Traditional CSS encourages you to create abstractions early. You name things, group styles into classes, and hope the names stay relevant as designs evolve. In practice, this leads to bloated stylesheets full of dead or duplicated CSS.

With utility-first CSS:

  • No naming fatigue — you never agonize over class names.
  • No dead CSS — utilities are only included if used.
  • Local reasoning — you see exactly what an element looks like by reading its classes.
  • Safe changes — editing one element never accidentally breaks another.

Common Utility Classes

Here is a practical example that uses many of the most common utilities:

<div class="max-w-md mx-auto bg-white rounded-lg shadow-md p-6">
  <h2 class="text-xl font-bold text-gray-900">Project Update</h2>
  <p class="mt-2 text-sm text-gray-600 leading-relaxed">
    The new dashboard is ready for review. We shipped three
    new chart components and improved load time by 40%.
  </p>
  <button class="mt-4 px-4 py-2 bg-blue-600 text-white text-sm font-medium rounded hover:bg-blue-700">
    View Details
  </button>
</div>

Breaking this down:

UtilityWhat it does
max-w-mdSets max-width: 28rem
mx-autoCenters horizontally via margin-left/right: auto
rounded-lgApplies border-radius: 0.5rem
shadow-mdAdds a medium box shadow
p-6Adds padding: 1.5rem on all sides
text-xlSets font-size: 1.25rem
font-boldSets font-weight: 700
leading-relaxedSets line-height: 1.625

Responsive Prefixes

Tailwind uses a mobile-first breakpoint system. Unprefixed utilities apply at all screen sizes; prefixed utilities apply at that breakpoint and above.

<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
  <div class="bg-white p-4 rounded shadow">Card 1</div>
  <div class="bg-white p-4 rounded shadow">Card 2</div>
  <div class="bg-white p-4 rounded shadow">Card 3</div>
</div>

Default breakpoints:

PrefixMin-widthTypical device
sm:640pxLarge phones
md:768pxTablets
lg:1024pxLaptops
xl:1280pxDesktops
2xl:1536pxLarge screens

You can also use max-* variants for max-width breakpoints:

<p class="max-md:text-center md:text-left">
  Centered on small screens, left-aligned on medium and up.
</p>

State Variants

Tailwind provides variants for every interactive and structural state:

<!-- Hover and focus states -->
<input
  class="border border-gray-300 rounded px-3 py-2
         hover:border-gray-400
         focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
  type="text"
  placeholder="Enter your email"
/>

<!-- Group hover: style children when a parent is hovered -->
<a href="#" class="group flex items-center gap-3 p-3 rounded-lg hover:bg-gray-100">
  <img class="w-10 h-10 rounded-full" src="/avatar.jpg" alt="" />
  <div>
    <p class="font-medium group-hover:text-blue-600">Jane Doe</p>
    <p class="text-sm text-gray-500">Engineer</p>
  </div>
</a>

<!-- First-child and odd/even -->
<ul class="divide-y divide-gray-200">
  <li class="py-3 first:pt-0 last:pb-0">Item</li>
</ul>

Common state variants include hover:, focus:, active:, disabled:, first:, last:, odd:, even:, group-hover:, and peer-*:.

Combining Variants

Variants can be stacked. They read left to right — "on medium screens, when hovered":

<button class="bg-blue-600 md:hover:bg-blue-800 text-white px-4 py-2 rounded">
  Save
</button>

Arbitrary Values

When Tailwind's default scale does not have the exact value you need, use square brackets:

<div class="top-[117px] bg-[#1a1a2e] text-[clamp(1rem,2.5vw,2rem)]">
  Custom values
</div>

This keeps you in the utility workflow without dropping into a CSS file.