Introduction
Tailwind CSS takes a fundamentally different approach to responsive design compared to writing custom media queries in vanilla CSS. Instead of switching to a separate stylesheet or writing @media blocks, you apply responsive variants directly to utility classes using breakpoint prefixes like sm:, md:, lg:. This mobile-first, utility-driven system lets you build fully responsive layouts without ever leaving your HTML.
This guide covers Tailwind's breakpoint system, mobile-first philosophy, responsive patterns for common layouts, and techniques for building adaptive components that work beautifully across all screen sizes.
Tailwind's Breakpoint System
Tailwind provides five default breakpoints, applied as prefixes to any utility class:
| Prefix | Minimum Width | Typical Devices | CSS Equivalent |
|---|
| (none) | 0px | Mobile (default) | No media query |
sm: | 640px | Large phones, landscape | @media (min-width: 640px) |
md: | 768px | Tablets | @media (min-width: 768px) |
lg: | 1024px | Laptops | @media (min-width: 1024px) |
xl: | 1280px | Desktops | @media (min-width: 1280px) |
2xl: | 1536px | Large desktops | @media (min-width: 1536px) |
Key principle: Unprefixed utilities apply to ALL screen sizes. Prefixed utilities apply at that breakpoint AND above.
Mobile-First Philosophy
Tailwind is mobile-first by design. You write styles for mobile first (no prefix), then layer on changes for larger screens:
<!-- CORRECT: Mobile-first approach -->
<div class="text-sm md:text-base lg:text-lg">
<!-- text-sm on mobile → text-base on tablet → text-lg on desktop -->
</div>
<!-- WRONG mental model: Don't think "desktop-first" -->
<!-- There's no "only on mobile" prefix — the base IS mobile -->
Reading Responsive Classes
Think of it as: "This style applies FROM this breakpoint upward"
<div class="w-full md:w-1/2 lg:w-1/3">
<!--
Mobile (0px+): full width
Tablet (768px+): half width
Desktop (1024px+): one-third width
-->
</div>
Responsive Layout Patterns
Pattern 1: Stack to Grid
The most common responsive pattern — elements stack vertically on mobile and arrange in a grid on larger screens:
<!-- Cards: stack on mobile, 2 columns on tablet, 3 on desktop -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div class="bg-white rounded-lg p-6 shadow">Card 1</div>
<div class="bg-white rounded-lg p-6 shadow">Card 2</div>
<div class="bg-white rounded-lg p-6 shadow">Card 3</div>
<div class="bg-white rounded-lg p-6 shadow">Card 4</div>
<div class="bg-white rounded-lg p-6 shadow">Card 5</div>
<div class="bg-white rounded-lg p-6 shadow">Card 6</div>
</div>
Pattern 2: Responsive Navigation
<nav class="bg-gray-900 text-white">
<div class="max-w-7xl mx-auto px-4 py-3 flex items-center justify-between">
<!-- Logo always visible -->
<a href="/" class="text-xl font-bold">Brand</a>
<!-- Nav links: hidden on mobile, flex on medium+ -->
<div class="hidden md:flex space-x-6">
<a href="/products" class="hover:text-gray-300">Products</a>
<a href="/about" class="hover:text-gray-300">About</a>
<a href="/contact" class="hover:text-gray-300">Contact</a>
</div>
<!-- Hamburger: visible on mobile, hidden on medium+ -->
<button class="md:hidden">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"/>
</svg>
</button>
</div>
</nav>
<div class="flex flex-col lg:flex-row min-h-screen">
<!-- Sidebar: full width top bar on mobile, fixed sidebar on desktop -->
<aside class="w-full lg:w-64 bg-gray-800 text-white p-4 lg:min-h-screen">
<h2 class="text-lg font-bold mb-4">Dashboard</h2>
<nav class="flex lg:flex-col space-x-4 lg:space-x-0 lg:space-y-2 overflow-x-auto">
<a href="#" class="whitespace-nowrap lg:whitespace-normal">Overview</a>
<a href="#" class="whitespace-nowrap lg:whitespace-normal">Analytics</a>
<a href="#" class="whitespace-nowrap lg:whitespace-normal">Settings</a>
</nav>
</aside>
<!-- Main content -->
<main class="flex-1 p-4 lg:p-8">
<h1 class="text-2xl lg:text-3xl font-bold">Welcome</h1>
</main>
</div>
Pattern 4: Responsive Hero Section
<section class="px-4 py-12 md:py-20 lg:py-32">
<div class="max-w-7xl mx-auto flex flex-col lg:flex-row items-center gap-8 lg:gap-16">
<!-- Text: full width on mobile, half on desktop -->
<div class="w-full lg:w-1/2 text-center lg:text-left">
<h1 class="text-3xl md:text-4xl lg:text-5xl xl:text-6xl font-bold">
Build Amazing Products
</h1>
<p class="mt-4 text-gray-600 text-base md:text-lg lg:text-xl">
Ship faster with our developer tools and APIs.
</p>
<div class="mt-6 flex flex-col sm:flex-row gap-3 justify-center lg:justify-start">
<a href="#" class="px-6 py-3 bg-blue-600 text-white rounded-lg text-center">
Get Started
</a>
<a href="#" class="px-6 py-3 border border-gray-300 rounded-lg text-center">
Learn More
</a>
</div>
</div>
<!-- Image: full width on mobile, half on desktop -->
<div class="w-full lg:w-1/2">
<img src="/hero.png" alt="Product" class="rounded-xl shadow-xl" />
</div>
</div>
</section>
Responsive Spacing and Typography
Adaptive Spacing
<!-- Padding increases with screen size -->
<div class="p-4 md:p-6 lg:p-8 xl:p-12">
<!-- 16px → 24px → 32px → 48px padding -->
</div>
<!-- Section spacing -->
<section class="my-8 md:my-12 lg:my-16">
<!-- Vertical margin grows on larger screens -->
</section>
<!-- Container with responsive max-width -->
<div class="mx-auto px-4 sm:px-6 lg:px-8 max-w-sm md:max-w-2xl lg:max-w-5xl xl:max-w-7xl">
<!-- Content area adapts to screen -->
</div>
Responsive Typography
<!-- Heading scales across breakpoints -->
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold leading-tight">
Responsive Heading
</h1>
<!-- Body text adjusts for readability -->
<p class="text-sm md:text-base lg:text-lg leading-relaxed max-w-prose">
Long form content stays readable at every size.
</p>
Responsive Show/Hide
Control element visibility at different breakpoints:
<!-- Show only on mobile -->
<div class="block md:hidden">Mobile-only content</div>
<!-- Show only on tablet and up -->
<div class="hidden md:block">Tablet and desktop content</div>
<!-- Show only on desktop -->
<div class="hidden lg:block">Desktop-only sidebar</div>
<!-- Show on mobile and desktop, hide on tablet -->
<div class="block md:hidden lg:block">Skip tablet</div>
Responsive Flexbox and Grid
Flex Direction Changes
<!-- Column on mobile, row on tablet+ -->
<div class="flex flex-col md:flex-row gap-4">
<div class="md:w-2/3">Main content</div>
<div class="md:w-1/3">Sidebar</div>
</div>
Grid Column Spans
<!-- Complex dashboard grid -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<!-- Stats: 1 col on mobile, spans 2 on tablet, spans 1 on desktop -->
<div class="bg-white p-4 rounded shadow">Stat 1</div>
<div class="bg-white p-4 rounded shadow">Stat 2</div>
<div class="bg-white p-4 rounded shadow">Stat 3</div>
<div class="bg-white p-4 rounded shadow">Stat 4</div>
<!-- Chart: full width on mobile/tablet, spans 3 cols on desktop -->
<div class="md:col-span-2 lg:col-span-3 bg-white p-4 rounded shadow">
Chart Area
</div>
<!-- Activity: full width on mobile, spans 1 on desktop -->
<div class="md:col-span-2 lg:col-span-1 bg-white p-4 rounded shadow">
Recent Activity
</div>
</div>
<!-- Responsive image sizing -->
<img
src="/photo.jpg"
alt="Example"
class="w-full md:w-3/4 lg:w-1/2 h-48 md:h-64 lg:h-80 object-cover rounded-lg"
/>
<!-- Aspect ratio containers -->
<div class="aspect-video md:aspect-[4/3] lg:aspect-[21/9]">
<img src="/banner.jpg" class="w-full h-full object-cover" />
</div>
<!-- Image grid: 2 cols on mobile, 4 on desktop -->
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-2">
<img class="aspect-square object-cover rounded" src="/1.jpg" />
<img class="aspect-square object-cover rounded" src="/2.jpg" />
<img class="aspect-square object-cover rounded" src="/3.jpg" />
<img class="aspect-square object-cover rounded" src="/4.jpg" />
</div>
Custom Breakpoints
Extend or override default breakpoints in tailwind.config.js:
// tailwind.config.js
module.exports = {
theme: {
screens: {
'xs': '475px', // Add extra-small breakpoint
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
'2xl': '1536px',
'3xl': '1920px', // Ultra-wide monitors
},
},
}
// Usage:
// <div class="xs:flex 3xl:max-w-screen-2xl">
Max-Width Breakpoints
Tailwind also supports max-width queries for desktop-first edge cases:
<!-- Apply ONLY below medium (max-width: 767px) -->
<div class="max-md:text-center">
Centered text on mobile only
</div>
<!-- Apply ONLY between sm and lg -->
<div class="sm:max-lg:grid-cols-2">
Two columns only on tablet
</div>
Responsive Component Example: Pricing Card
<div class="max-w-7xl mx-auto px-4 py-8 md:py-16">
<h2 class="text-2xl md:text-3xl font-bold text-center mb-8">Pricing</h2>
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 lg:gap-8">
<!-- Basic Plan -->
<div class="border rounded-xl p-6 lg:p-8 flex flex-col">
<h3 class="text-lg font-semibold">Basic</h3>
<p class="text-3xl lg:text-4xl font-bold mt-2">$9<span class="text-base font-normal">/mo</span></p>
<ul class="mt-6 space-y-3 flex-1 text-sm lg:text-base">
<li class="flex items-center gap-2">✓ 5 Projects</li>
<li class="flex items-center gap-2">✓ 10GB Storage</li>
<li class="flex items-center gap-2">✓ Email Support</li>
</ul>
<button class="mt-6 w-full py-2.5 lg:py-3 border border-blue-600 text-blue-600 rounded-lg
hover:bg-blue-50 transition">
Choose Basic
</button>
</div>
<!-- Pro Plan (featured) -->
<div class="border-2 border-blue-600 rounded-xl p-6 lg:p-8 flex flex-col
relative md:-mt-4 md:mb-4 shadow-lg">
<span class="absolute -top-3 left-1/2 -translate-x-1/2 bg-blue-600 text-white
text-xs px-3 py-1 rounded-full">Most Popular</span>
<h3 class="text-lg font-semibold">Pro</h3>
<p class="text-3xl lg:text-4xl font-bold mt-2">$29<span class="text-base font-normal">/mo</span></p>
<ul class="mt-6 space-y-3 flex-1 text-sm lg:text-base">
<li class="flex items-center gap-2">✓ Unlimited Projects</li>
<li class="flex items-center gap-2">✓ 100GB Storage</li>
<li class="flex items-center gap-2">✓ Priority Support</li>
<li class="flex items-center gap-2">✓ Analytics Dashboard</li>
</ul>
<button class="mt-6 w-full py-2.5 lg:py-3 bg-blue-600 text-white rounded-lg
hover:bg-blue-700 transition">
Choose Pro
</button>
</div>
<!-- Enterprise Plan -->
<div class="border rounded-xl p-6 lg:p-8 flex flex-col">
<h3 class="text-lg font-semibold">Enterprise</h3>
<p class="text-3xl lg:text-4xl font-bold mt-2">$99<span class="text-base font-normal">/mo</span></p>
<ul class="mt-6 space-y-3 flex-1 text-sm lg:text-base">
<li class="flex items-center gap-2">✓ Everything in Pro</li>
<li class="flex items-center gap-2">✓ Unlimited Storage</li>
<li class="flex items-center gap-2">✓ Dedicated Manager</li>
<li class="flex items-center gap-2">✓ Custom Integrations</li>
<li class="flex items-center gap-2">✓ SLA Guarantee</li>
</ul>
<button class="mt-6 w-full py-2.5 lg:py-3 border border-blue-600 text-blue-600 rounded-lg
hover:bg-blue-50 transition">
Contact Sales
</button>
</div>
</div>
</div>
Best Practices
1. Always Start Mobile-First
Design for the smallest screen first, then add complexity for larger screens. This ensures your core experience works everywhere.
2. Use Consistent Breakpoint Jumps
Don't skip breakpoints randomly. If content changes at md:, check if it also needs adjustment at lg:.
3. Test at Breakpoint Boundaries
Resize your browser to 639px, 640px, 767px, 768px, etc. to catch awkward in-between states.
4. Combine with Container Queries (Tailwind v3.4+)
<div class="@container">
<div class="@sm:flex @lg:grid @lg:grid-cols-3">
<!-- Responds to parent container width, not viewport -->
</div>
</div>
5. Keep Classes Readable
For complex responsive patterns, extract components or use @apply in CSS:
/* When class lists get too long */
.card {
@apply w-full p-4 rounded-lg shadow;
@apply md:w-1/2 md:p-6;
@apply lg:w-1/3 lg:p-8;
}
Interview Questions
Answer: Traditional CSS writes separate @media blocks in stylesheets. Tailwind applies responsive changes inline using breakpoint prefixes (md:flex). Tailwind is mobile-first by default — unprefixed classes are the mobile base, and prefixes add changes for larger screens. This co-locates responsive logic with the element rather than separating it into distant CSS files.
Q2: What does mobile-first mean in Tailwind?
Answer: Mobile-first means unprefixed utilities define the mobile/default styles, and breakpoint prefixes apply FROM that breakpoint and up. text-sm md:text-base means small text by default (all screens), base text from 768px upward. There's no "mobile-only" prefix because the base IS mobile.
Q3: How would you hide an element on mobile but show it on desktop?
Answer: Use hidden lg:block. The hidden class applies to all screens (including mobile), and lg:block overrides it from 1024px upward. For the reverse (show on mobile, hide on desktop), use block lg:hidden.
Q4: Can you create custom breakpoints in Tailwind?
Answer: Yes, in tailwind.config.js under theme.screens. You can add new breakpoints like 'xs': '475px' or '3xl': '1920px'. You can also use max- prefixes for max-width queries and range syntax like sm:max-lg: for targeting specific ranges.
Quick Revision Notes
- No prefix = Mobile/all screens (0px+)
- sm: = 640px+, md: = 768px+, lg: = 1024px+, xl: = 1280px+, 2xl: = 1536px+
- Mobile-first = Base styles are mobile, add complexity going up
- hidden md:block = Hide on mobile, show on tablet+
- grid-cols-1 md:grid-cols-2 lg:grid-cols-3 = Common responsive grid
- flex-col md:flex-row = Stack on mobile, side-by-side on tablet+
- max-md: = Apply only below medium (max-width variant)
- @container = Container queries for component-level responsiveness
- Always test at breakpoint boundaries (e.g., 767px and 768px)
Summary
Tailwind CSS makes responsive design declarative and co-located with your markup. By applying breakpoint prefixes (sm:, md:, lg:, xl:, 2xl:) to any utility class, you build mobile-first responsive layouts without writing a single media query manually. The utility-first approach means every responsive decision is visible right in the HTML, making it easy to understand how a component adapts across screen sizes at a glance.