Tailwind CSS・Reacting to state and screen width

Switching by screen width (md: and lg:)

Put md: in front of a class and it means "at this width and up." How you get responsive without writing media queries, and why having only min-width—mobile-first, enforced—is actually a gift.

Responsive Tailwind is just putting a prefix in front of a class. You never write a media query.

<!-- stacked on phones, side by side at 768px and up -->
<div class="flex flex-col md:flex-row gap-4">
  <div>1</div>
  <div>2</div>
</div>

md:flex-row means “flex-direction: row only at 768px and up.” In plain CSS:

.box {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
@media (min-width: 768px) {
  .box {
    flex-direction: row;
  }
}

The same thing, in one line of HTML.

TipsHow to choose your breakpointsHow to choose breakpoints in the first place, in this quick reference

The five prefixes

Tailwind ships five dividing lines.

PrefixTakes effect fromIntended for
(none)Every widthPhones (the base)
sm:640px and upLarger phones
md:768px and upTablets
lg:1024px and upDesktop
xl:1280px and upLarge screens
2xl:1536px and upExtra large

In practice you’ll use md: and lg:. “Two columns from tablet, three from desktop” needs only those two.

<!-- one column on phones → two on tablet → three on desktop -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  <div class="p-4 bg-white rounded-xl">1</div>
  <div class="p-4 bg-white rounded-xl">2</div>
  <div class="p-4 bg-white rounded-xl">3</div>
</div>

Read left to right, narrow to wide—that’s how responsive Tailwind reads.

Prefixes are always “and up”

This is Tailwind’s biggest design decision. Every prefix is min-width—“at this width and up.” There is no other direction.

Which fixes the way you write:

  • No prefix = the phone look (the base)
  • Prefix = an override for wider screens

In other words mobile-first is enforced. There’s no room to wonder “should I write this with max-width?”

Showing and hiding

“Hamburger on phones, a row of links on desktop”—the classic—is prefixes alone.

<!-- only appears on phones -->
<button class="md:hidden">Menu</button>

<!-- only appears on desktop -->
<nav class="hidden md:flex gap-4">
  <a href="#">Home</a>
  <a href="#">About</a>
</nav>

Read them as:

  • md:hidden—visible normally, hidden at 768px and up
  • hidden md:flex—hidden normally, display: flex at 768px and up

hidden is display: none. It’s md:flex rather than md:block because we want that nav laid out in a row. Being able to say how it appears is what’s nice about this form.

Switching type sizes and spacing too

A heading at the same size on phones and desktop always looks wrong on one of them.

<h1 class="text-2xl md:text-4xl font-bold">
  Shima's page
</h1>

24px on phones, 36px at 768px and up. Spacing switches the same way.

<section class="px-4 py-8 md:px-8 md:py-16">
  ...
</section>

Four combinations you’ll reuse

Stacked on phones, row on desktop

<div class="flex flex-col md:flex-row gap-4">

More columns as the screen grows

<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">

Full width on phones, fixed sidebar on desktop

<aside class="w-full md:w-60 md:shrink-0">

Capped content width (centred at any size)

<div class="max-w-4xl mx-auto px-4 md:px-8">

That last one only has a prefix on the padding. max-w-4xl mx-auto works at every width and shrinks on its own when the screen is narrow, so no switching is needed. Preferring forms that don’t need switching at all is the same instinct as in plain CSS.

Keeping long class lists readable

As prefixes multiply, the lists get long. The trick to keeping them readable is fixing the order.

<!-- recommended: group narrow-screen first, then wider -->
<div class="grid grid-cols-1 gap-4 p-4 md:grid-cols-2 md:gap-6 md:p-8 lg:grid-cols-3">

All the unprefixed ones first, then all the md:, then lg:. Just sorting them this way makes them far easier to read. There are tools that reorder automatically, but doing it deliberately by hand is plenty to start.

Summary of this lesson

  1. Put md: in front of a class and it means “at this width and up
  2. Every prefix is min-width—which is why mobile-first is enforced
  3. No prefix = phone, prefix = wider. Read left to right, narrow to wide
  4. Mistaking md: for “phones” inverts your show/hide logic
  5. You’ll use md: and lg:. Prefer forms that need no switching at all

Next: the hover: and focus: prefixes that react to state. The mechanism is identical to md:.

FAQ

How do I make things responsive in Tailwind?
Put a prefix in front of the class. md:flex means "display: flex only at 768px and up." You never write a media query yourself.
Is md: for phones or for desktop?
For the wider end. Every Tailwind width prefix is min-width—"at this width and up"—so no prefix means phone, and md: or lg: means the wider screens.
Can I write max-width instead?
You can with max-md:, but generally don't. Once the one-way rule (no prefix = phone, prefix = wider) breaks down, you can no longer trace which declaration is winning.
Can I change the breakpoint values?
You can, but try building with the defaults first (640, 768, 1024, 1280, 1536px). Changing them costs you a shared understanding across the team, so have a reason before you do.