Skip to content

Tailwind CSS + shadcn/ui — Responsive Design

OWNER: alexander ALSO_USED_BY: floris, floor LAST_VERIFIED: 2026-03-26 GE_STACK_VERSION: tailwindcss ^4


Overview

Every GE project is mobile-first. Base styles target the smallest viewport. Breakpoint prefixes layer on larger-screen overrides. Tailwind v4 adds native container queries — use them for component-level responsiveness. Agents use this page when implementing responsive layouts.


Mobile-First Principle

CHECK: You are writing responsive styles. THEN: Write mobile styles first (no prefix), then add breakpoint prefixes for larger screens.

{/* CORRECT: mobile-first */}
<div className="flex flex-col gap-4 md:flex-row md:gap-6 lg:gap-8">

{/* WRONG: desktop-first (overriding down) */}
<div className="flex flex-row gap-8 max-md:flex-col max-md:gap-4">

ANTI_PATTERN: Using max-* variants as the primary responsive strategy. FIX: Start with mobile, add sm:, md:, lg: progressively. Use max-* only for rare exceptions.


Breakpoint Strategy

Prefix Min-width GE usage
(none) 0px Single-column, stacked layout
sm: 640px Two-column optional, slightly wider spacing
md: 768px Sidebar appears, grid layouts activate
lg: 1024px Full desktop layout, max content width
xl: 1280px Wider spacing, optional extra columns
2xl: 1536px Ultrawide — cap content width, center

CHECK: A layout shift happens. IF: Sidebar appears/disappears. THEN: Use md: — tablet is the sidebar breakpoint in GE. IF: Navigation changes from hamburger to full. THEN: Use lg: — desktop is the nav breakpoint.


Container Queries (Tailwind v4 Native)

Container queries are built into Tailwind v4 — no plugin needed. Use them for components that must adapt to their container, not the viewport.

{/* Mark the container */}
<div className="@container">
  {/* Respond to container width */}
  <div className="flex flex-col @md:flex-row @lg:grid @lg:grid-cols-3">
    {/* Content */}
  </div>
</div>

CHECK: A component needs to be responsive. IF: The component is used in different layout contexts (sidebar, main, full-width). THEN: Use container queries (@container + @md:, @lg:). IF: The component always lives in the same layout context. THEN: Use viewport breakpoints (md:, lg:).

Container query breakpoints: @xs (320px), @sm (384px), @md (448px), @lg (512px), @xl (576px), @2xl (672px), etc.

CHECK: You need a container query range. IF: Maximum width container query needed. THEN: Use @max-md: syntax (Tailwind v4 native). IF: Range needed. THEN: Stack: @min-sm:@max-lg:flex-row.


Common Responsive Patterns

Responsive Grid

<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
  {items.map(item => <Card key={item.id} {...item} />)}
</div>

Responsive Sidebar Layout

<div className="flex min-h-screen flex-col md:flex-row">
  <aside className="w-full border-b md:w-64 md:border-b-0 md:border-r">
    <nav className="p-4">{/* Sidebar nav */}</nav>
  </aside>
  <main className="flex-1 p-4 md:p-6 lg:p-8">
    {/* Content */}
  </main>
</div>

Responsive Text

<h1 className="text-2xl font-bold sm:text-3xl lg:text-4xl">
  {title}
</h1>

Responsive Spacing

<section className="px-4 py-8 sm:px-6 sm:py-12 lg:px-8 lg:py-16">
  {/* Section content */}
</section>

Hide/Show by Breakpoint

{/* Mobile only */}
<MobileNav className="md:hidden" />

{/* Desktop only */}
<DesktopNav className="hidden md:flex" />

CHECK: You are hiding an element at certain breakpoints. THEN: Use hidden + {bp}:block or {bp}:flex — never display: none in inline styles.


Max Width Containers

GE caps content width to prevent ultra-wide readability issues.

<div className="mx-auto w-full max-w-7xl px-4 sm:px-6 lg:px-8">
  {/* Page content */}
</div>

CHECK: A page layout component is being built. THEN: Apply max-w-7xl mx-auto (or max-w-5xl for text-heavy pages). THEN: Add horizontal padding that scales with breakpoints.


Touch Targets

CHECK: An interactive element is on mobile. THEN: Minimum touch target is 44x44px (WCAG 2.1). THEN: Use min-h-11 min-w-11 (44px) on buttons/links in mobile contexts.

ANTI_PATTERN: Icon buttons with h-6 w-6 and no padding on mobile. FIX: Wrap with clickable area: p-2 on a 24px icon gives 40px+ touch target.


Images and Media

<img
  src={src}
  alt={alt}
  className="h-auto w-full rounded-lg object-cover sm:max-w-md lg:max-w-lg"
/>

CHECK: An image is displayed. THEN: Always set w-full h-auto as base — images must not overflow on mobile. THEN: Use object-cover or object-contain to control aspect ratio. THEN: Set max-w-* on larger breakpoints to prevent oversized images on desktop.


Cross-References

READ_ALSO: wiki/docs/stack/tailwind-shadcn/index.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/design-tokens.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/pitfalls.md READ_ALSO: wiki/docs/stack/tailwind-shadcn/checklist.md