Skip to main content
Technology & EngineeringDesign Systems203 lines

Responsive Patterns

Responsive design patterns, fluid layouts, and adaptive component strategies for design systems

Quick Summary18 lines
You are an expert in responsive design patterns for building and maintaining design systems.

## Key Points

- **Fluid** — widths use percentages or `fr` units; content reflows naturally.
- **Adaptive** — component swaps its structure at breakpoints (e.g., tabs become an accordion on mobile).
- **Container queries** — components respond to their parent width, not the viewport, enabling truly reusable layout-agnostic components.
- **Stack** — vertical spacing with consistent gap
- **Cluster** — horizontal wrapping with gap
- **Grid** — auto-fit/auto-fill responsive grid
- **Sidebar** — content + fixed-width sidebar that collapses below a threshold
- Prefer container queries over media queries for component-level responsiveness so components adapt to their available space rather than the viewport.
- Use CSS `clamp()` for fluid spacing and typography instead of discrete breakpoint jumps, providing smoother scaling across all screen sizes.
- Provide responsive layout primitives (Stack, Grid, Sidebar) in the system so product teams do not reinvent responsive logic in every feature.
- Testing only at exact breakpoint boundaries and missing layout issues at in-between sizes where content may overflow or wrap awkwardly.
- Using `display: none` to hide desktop elements on mobile instead of building truly adaptive components, which ships unnecessary markup and hurts performance.
skilldb get design-systems-skills/Responsive PatternsFull skill: 203 lines
Paste into your CLAUDE.md or agent config

Responsive Patterns — Design Systems

You are an expert in responsive design patterns for building and maintaining design systems.

Overview

Responsive patterns in a design system define how components and layouts adapt across viewport sizes, input modes, and device capabilities. Rather than leaving responsive behavior to each product team, the system provides layout primitives, breakpoint tokens, and adaptive component variants that ensure consistent behavior everywhere.

Core Philosophy

Responsive design at the system level means providing layout primitives and adaptive patterns that product teams compose, rather than leaving each team to reinvent responsive behavior independently. When the system ships a Grid component with a minItemWidth prop, a Stack with fluid spacing, and a Sidebar layout that collapses at a configurable threshold, product teams get correct responsive behavior by default instead of writing custom media queries.

The shift from viewport-based media queries to container queries represents a fundamental change in how responsive components should be built. A card component should not care about the viewport width — it should care about how much space it has been given. Container queries enable truly reusable components that adapt to their context, whether they are in a three-column grid, a sidebar, or a full-width hero section. Design systems should adopt container queries as the primary responsive mechanism for component-level layout.

Fluid design using clamp() for spacing and typography produces smoother results than discrete breakpoint jumps. Rather than text that snaps from 1rem to 1.25rem at exactly 768px, fluid typography scales continuously across all viewport widths. This eliminates the jarring layout shifts at breakpoint boundaries and produces a polished experience on every screen size, not just the ones you tested.

Core Concepts

Breakpoint Tokens

Define a shared set of breakpoints used across all layout utilities and components:

TokenValueTarget
sm640pxLarge phones landscape
md768pxTablets portrait
lg1024pxTablets landscape, small laptops
xl1280pxDesktops
2xl1536pxLarge desktops

Layout Strategies

  • Fluid — widths use percentages or fr units; content reflows naturally.
  • Adaptive — component swaps its structure at breakpoints (e.g., tabs become an accordion on mobile).
  • Container queries — components respond to their parent width, not the viewport, enabling truly reusable layout-agnostic components.

Responsive Primitives

A design system should provide low-level layout components that handle the most common responsive patterns:

  • Stack — vertical spacing with consistent gap
  • Cluster — horizontal wrapping with gap
  • Grid — auto-fit/auto-fill responsive grid
  • Sidebar — content + fixed-width sidebar that collapses below a threshold

Implementation Patterns

Fluid Grid Component

interface GridProps {
  /** Minimum column width before wrapping */
  minItemWidth?: string;
  /** Gap between items */
  gap?: string;
  children: React.ReactNode;
}

export function Grid({
  minItemWidth = '16rem',
  gap = 'var(--space-4)',
  children,
}: GridProps) {
  return (
    <div
      style={{
        display: 'grid',
        gridTemplateColumns: `repeat(auto-fill, minmax(min(${minItemWidth}, 100%), 1fr))`,
        gap,
      }}
    >
      {children}
    </div>
  );
}

Container Query Responsive Card

.card-container {
  container-type: inline-size;
  container-name: card;
}

.card {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

/* When the container (not viewport) is wide enough, go horizontal */
@container card (min-width: 400px) {
  .card {
    grid-template-columns: 200px 1fr;
  }
}

@container card (min-width: 600px) {
  .card {
    grid-template-columns: 280px 1fr;
  }
}

Responsive Navigation Pattern

import { useState, useEffect } from 'react';

function useMediaQuery(query: string) {
  const [matches, setMatches] = useState(
    () => window.matchMedia(query).matches
  );

  useEffect(() => {
    const mql = window.matchMedia(query);
    const handler = (e: MediaQueryListEvent) => setMatches(e.matches);
    mql.addEventListener('change', handler);
    return () => mql.removeEventListener('change', handler);
  }, [query]);

  return matches;
}

export function Navigation({ items }: { items: NavItem[] }) {
  const isDesktop = useMediaQuery('(min-width: 1024px)');

  return isDesktop ? (
    <nav>
      <ul style={{ display: 'flex', gap: 'var(--space-4)' }}>
        {items.map((item) => (
          <li key={item.href}><a href={item.href}>{item.label}</a></li>
        ))}
      </ul>
    </nav>
  ) : (
    <MobileDrawerNav items={items} />
  );
}

Responsive Spacing Utility

/* Fluid spacing that scales with viewport */
:root {
  --space-fluid-sm: clamp(0.5rem, 0.3rem + 1vw, 1rem);
  --space-fluid-md: clamp(1rem, 0.5rem + 2vw, 2rem);
  --space-fluid-lg: clamp(1.5rem, 1rem + 3vw, 3rem);
}

/* Responsive stack component */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-fluid-md);
}

.stack[data-spacing="tight"] { gap: var(--space-fluid-sm); }
.stack[data-spacing="loose"] { gap: var(--space-fluid-lg); }

Fluid Typography

:root {
  --font-size-base: clamp(1rem, 0.925rem + 0.375vw, 1.125rem);
  --font-size-lg: clamp(1.125rem, 1rem + 0.5vw, 1.375rem);
  --font-size-xl: clamp(1.25rem, 1rem + 1.25vw, 2rem);
  --font-size-2xl: clamp(1.5rem, 1rem + 2.5vw, 3rem);
}

Best Practices

  • Prefer container queries over media queries for component-level responsiveness so components adapt to their available space rather than the viewport.
  • Use CSS clamp() for fluid spacing and typography instead of discrete breakpoint jumps, providing smoother scaling across all screen sizes.
  • Provide responsive layout primitives (Stack, Grid, Sidebar) in the system so product teams do not reinvent responsive logic in every feature.

Common Pitfalls

  • Testing only at exact breakpoint boundaries and missing layout issues at in-between sizes where content may overflow or wrap awkwardly.
  • Using display: none to hide desktop elements on mobile instead of building truly adaptive components, which ships unnecessary markup and hurts performance.

Anti-Patterns

  • Every component owns its own breakpoints. When individual components define ad-hoc media queries at arbitrary pixel values, the system has no consistent responsive behavior. Breakpoints should be shared tokens that all layout components reference.

  • Viewport media queries for component layout. A card component that uses @media (min-width: 768px) to switch from vertical to horizontal layout breaks when placed in a narrow sidebar on a wide screen. Use container queries so components respond to their available space, not the viewport.

  • display: none as a responsive strategy. Hiding fully rendered desktop markup on mobile with display: none still ships all the HTML, CSS, and JavaScript to the client. Build adaptive components that conditionally render only the structure appropriate for the current context.

  • Testing only at standard breakpoints. Verifying layouts at exactly 768px and 1024px misses problems at in-between sizes where content overflows, text wraps awkwardly, or flex items compress below their minimum useful width. Test at arbitrary sizes across the full range.

  • Fixed-pixel layouts at any viewport. Using hardcoded pixel widths like width: 1200px for page containers or width: 300px for sidebars creates brittle layouts that do not adapt. Use relative units, max-width constraints, and fluid sizing so layouts remain flexible.

Install this skill directly: skilldb add design-systems-skills

Get CLI access →