Skip to content
Responsive Design logo

Responsive Design

> **Skill Purpose:** Mobile-first design implementation, breakpoint management, and responsive component patterns

Coverage-Creatives/zeus0installs0stars

SKILL.md

Full skill instructions

Responsive Design

Skill Purpose: Mobile-first design implementation, breakpoint management, and responsive component patterns


Core Skill Pattern

Objective: Establish comprehensive responsive design strategy with mobile-first approach, breakpoint management, and cross-device compatibility.

Universal Pattern:

  1. Define responsive design strategy and approach
  2. Create breakpoint management and grid systems
  3. Establish responsive component patterns
  4. Set up mobile-first design procedures
  5. Create responsive testing and validation procedures

Key Decisions (Project-Specific):

  • Breakpoint strategy and screen size targets
  • Mobile-first vs desktop-first approach
  • Grid system and layout framework
  • Component responsive behavior patterns
  • Testing approach and device coverage

Project-Specific Implementation Notes

Customize per project:

  • Breakpoints based on target devices and usage patterns
  • Grid system based on layout complexity and framework
  • Component patterns based on UI library and design system
  • Testing depth based on device support requirements
  • Performance considerations for mobile devices

Example Implementation (Tailwind CSS Responsive Pattern)

Note: This is an example pattern using Tailwind CSS with mobile-first design. Adapt responsive framework and patterns based on your specific project requirements and design system.

Prerequisites (Example)

  • Tailwind CSS configured and integrated
  • Design system breakpoints defined
  • Component library (shadcn/​ui) set up
  • Responsive testing tools configured

Example: Responsive Design Implementation

Framework-Specific Example: This demonstrates responsive patterns with Tailwind CSS and Next.js. Adapt for your responsive framework and component library requirements.

Responsive Configuration

// tailwind.config.ts
import type { Config } from 'tailwindcss';

const config: Config = {
  content: [
    './​pages/​**/​*.{js,ts,jsx,tsx,mdx}',
    './​components/​**/​*.{js,ts,jsx,tsx,mdx}',
    './​app/​**/​*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    extend: {
      screens: {
        'xs': '475px',  // Extra small screens
        'sm': '640px',  // Small screens
        'md': '768px',  // Medium screens (tablets)
        'lg': '1024px', // Large screens (laptops)
        'xl': '1280px', // Extra large screens
        '2xl': '1536px', // 2X large screens
      },
      container: {
        center: true,
        padding: {
          DEFAULT: '1rem',
          sm: '2rem',
          lg: '4rem',
          xl: '5rem',
          '2xl': '6rem',
        },
      },
    },
  },
  plugins: [],
};

export default config;

Responsive Grid System

// components/​ui/​responsive-grid.tsx
import React from 'react';
import { cn } from '@/​lib/​utils';

interface ResponsiveGridProps {
  children: React.ReactNode;
  cols?: {
    xs?: number;
    sm?: number;
    md?: number;
    lg?: number;
    xl?: number;
    '2xl'?: number;
  };
  gap?: string;
  className?: string;
}

export function ResponsiveGrid({
  children,
  cols = { xs: 1, sm: 2, md: 3, lg: 4 },
  gap = 'gap-4',
  className
}: ResponsiveGridProps) {
  const gridClasses = cn(
    'grid',
    gap,
    {
      'grid-cols-1': cols.xs === 1,
      'grid-cols-2': cols.xs === 2,
      'grid-cols-3': cols.xs === 3,
      'grid-cols-4': cols.xs === 4,
      'grid-cols-5': cols.xs === 5,
      'grid-cols-6': cols.xs === 6,
    },
    {
      'sm:grid-cols-1': cols.sm === 1,
      'sm:grid-cols-2': cols.sm === 2,
      'sm:grid-cols-3': cols.sm === 3,
      'sm:grid-cols-4': cols.sm === 4,
      'sm:grid-cols-5': cols.sm === 5,
      'sm:grid-cols-6': cols.sm === 6,
    },
    {
      'md:grid-cols-1': cols.md === 1,
      'md:grid-cols-2': cols.md === 2,
      'md:grid-cols-3': cols.md === 3,
      'md:grid-cols-4': cols.md === 4,
      'md:grid-cols-5': cols.md === 5,
      'md:grid-cols-6': cols.md === 6,
    },
    {
      'lg:grid-cols-1': cols.lg === 1,
      'lg:grid-cols-2': cols.lg === 2,
      'lg:grid-cols-3': cols.lg === 3,
      'lg:grid-cols-4': cols.lg === 4,
      'lg:grid-cols-5': cols.lg === 5,
      'lg:grid-cols-6': cols.lg === 6,
    },
    {
      'xl:grid-cols-1': cols.xl === 1,
      'xl:grid-cols-2': cols.xl === 2,
      'xl:grid-cols-3': cols.xl === 3,
      'xl:grid-cols-4': cols.xl === 4,
      'xl:grid-cols-5': cols.xl === 5,
      'xl:grid-cols-6': cols.xl === 6,
    },
    className
  );

  return <div className={gridClasses}>{children}</​div>;
}

Responsive Container Component

// components/​ui/​responsive-container.tsx
import React from 'react';
import { cn } from '@/​lib/​utils';

interface ResponsiveContainerProps {
  children: React.ReactNode;
  size?: 'sm' | 'md' | 'lg' | 'xl' | 'full';
  className?: string;
}

export function ResponsiveContainer({
  children,
  size = 'lg',
  className
}: ResponsiveContainerProps) {
  const sizeClasses = {
    sm: 'max-w-sm',
    md: 'max-w-md', 
    lg: 'max-w-lg',
    xl: 'max-w-xl',
    full: 'max-w-full'
  };

  return (
    <div className={cn(
      'mx-auto px-4 sm:px-6 lg:px-8',
      sizeClasses[size],
      className
    )}>
      {children}
    </​div>
  );
}

Responsive Navigation Component

// components/​ui/​responsive-navigation.tsx
import React, { useState } from 'react';
import { AccessibleButton } from './​accessible-button';

interface ResponsiveNavigationProps {
  items: Array<{
    label: string;
    href: string;
    active?: boolean;
  }>;
}

export function ResponsiveNavigation({ items }: ResponsiveNavigationProps) {
  const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);

  return (
    <nav className="bg-white shadow-sm" role="navigation" aria-label="Main navigation">
      <div className="mx-auto px-4 sm:px-6 lg:px-8">
        <div className="flex justify-between h-16">
          {/​* Logo/​Brand - visible on all screens */​}
          <div className="flex items-center">
            <div className="flex-shrink-0">
              <h1 className="text-xl font-bold">Brand</​h1>
            </​div>
          </​div>

          {/​* Desktop Navigation - hidden on mobile */​}
          <div className="hidden md:flex items-center space-x-8">
            {items.map((item) => (
              <a
                key={item.href}
                href={item.href}
                className={cn(
                  'px-3 py-2 rounded-md text-sm font-medium',
                  item.active
                    ? 'bg-primary text-primary-foreground'
                    : 'text-gray-700 hover:text-gray-900 hover:bg-gray-100'
                )}
                aria-current={item.active ? 'page' : undefined}
              >
                {item.label}
              </​a>
            ))}
          </​div>

          {/​* Mobile menu button - visible only on mobile */​}
          <div className="md:hidden flex items-center">
            <AccessibleButton
              onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
              aria-expanded={isMobileMenuOpen}
              aria-label="Toggle navigation menu"
              className="p-2 rounded-md text-gray-700 hover:text-gray-900 hover:bg-gray-100"
            >
              <svg
                className="h-6 w-6"
                fill="none"
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth="2"
                viewBox="0 0 24 24"
                stroke="currentColor"
              >
                {isMobileMenuOpen ? (
                  <path d="M6 18L18 6M6 6l12 12" />
                ) : (
                  <path d="M4 6h16M4 12h16M4 18h16" />
                )}
              </​svg>
            </​AccessibleButton>
          </​div>
        </​div>

        {/​* Mobile Navigation Menu - visible only when open on mobile */​}
        {isMobileMenuOpen && (
          <div className="md:hidden">
            <div className="px-2 pt-2 pb-3 space-y-1 sm:px-3">
              {items.map((item) => (
                <a
                  key={item.href}
                  href={item.href}
                  className={cn(
                    'block px-3 py-2 rounded-md text-base font-medium',
                    item.active
                      ? 'bg-primary text-primary-foreground'
                      : 'text-gray-700 hover:text-gray-900 hover:bg-gray-100'
                  )}
                  aria-current={item.active ? 'page' : undefined}
                  onClick={() => setIsMobileMenuOpen(false)}
                >
                  {item.label}
                </​a>
              ))}
            </​div>
          </​div>
        )}
      </​div>
    </​nav>
  );
}

Responsive Card Component

// components/​ui/​responsive-card.tsx
import React from 'react';
import { cn } from '@/​lib/​utils';

interface ResponsiveCardProps {
  children: React.ReactNode;
  variant?: 'default' | 'compact' | 'expanded';
  className?: string;
}

export function ResponsiveCard({
  children,
  variant = 'default',
  className
}: ResponsiveCardProps) {
  const variantClasses = {
    default: 'p-4 sm:p-6',
    compact: 'p-3 sm:p-4',
    expanded: 'p-6 sm:p-8'
  };

  return (
    <div className={cn(
      'bg-white rounded-lg shadow-sm border border-gray-200',
      'transition-shadow duration-200 hover:shadow-md',
      variantClasses[variant],
      className
    )}>
      {children}
    </​div>
  );
}

// Usage example with responsive content
export function ResponsiveProductCard({ product }: { product: any }) {
  return (
    <ResponsiveCard variant="compact">
      <div className="space-y-4">
        {/​* Product image - responsive sizing */​}
        <div className="aspect-square w-full sm:w-48 sm:h-48 mx-auto bg-gray-100 rounded-lg overflow-hidden">
          <img
            src={product.image}
            alt={product.name}
            className="w-full h-full object-cover"
          />
        </​div>

        {/​* Product info - responsive text sizing */​}
        <div className="text-center sm:text-left">
          <h3 className="text-lg sm:text-xl font-semibold text-gray-900 line-clamp-2">
            {product.name}
          </​h3>
          <p className="text-sm sm:text-base text-gray-600 mt-1 line-clamp-3">
            {product.description}
          </​p>
          <div className="mt-4 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
            <span className="text-xl sm:text-2xl font-bold text-primary">
              ${product.price}
            </​span>
            <AccessibleButton className="w-full sm:w-auto">
              Add to Cart
            </​AccessibleButton>
          </​div>
        </​div>
      </​div>
    </​ResponsiveCard>
  );
}

Responsive Layout Component

// components/​ui/​responsive-layout.tsx
import React from 'react';
import { ResponsiveContainer } from './​responsive-container';
import { ResponsiveNavigation } from './​responsive-navigation';

interface ResponsiveLayoutProps {
  children: React.ReactNode;
  navigation?: Array<{
    label: string;
    href: string;
    active?: boolean;
  }>;
}

export function ResponsiveLayout({ children, navigation }: ResponsiveLayoutProps) {
  return (
    <div className="min-h-screen bg-gray-50">
      {/​* Responsive Navigation */​}
      {navigation && <ResponsiveNavigation items={navigation} />}

      {/​* Main Content */​}
      <main id="main-content" className="py-6 sm:py-8 lg:py-12">
        <ResponsiveContainer size="xl">
          {children}
        </​ResponsiveContainer>
      </​main>

      {/​* Responsive Footer */​}
      <footer className="bg-white border-t border-gray-200 mt-auto">
        <ResponsiveContainer size="lg">
          <div className="py-8 sm:py-12">
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8">
              {/​* Footer content with responsive columns */​}
              <div className="space-y-4">
                <h3 className="text-lg font-semibold">Company</​h3>
                <ul className="space-y-2">
                  <li><a href="#" className="text-gray-600 hover:text-gray-900">About</​a></​li>
                  <li><a href="#" className="text-gray-600 hover:text-gray-900">Contact</​a></​li>
                </​ul>
              </​div>
              {/​* Additional footer sections */​}
            </​div>
          </​div>
        </​ResponsiveContainer>
      </​footer>
    </​div>
  );
}

Responsive Utilities

// lib/​responsive-utils.ts
export class ResponsiveUtils {
  static getBreakpoint(): string {
    if (typeof window === 'undefined') return 'lg';
    
    const width = window.innerWidth;
    if (width < 475) return 'xs';
    if (width < 640) return 'sm';
    if (width < 768) return 'md';
    if (width < 1024) return 'lg';
    if (width < 1280) return 'xl';
    return '2xl';
  }

  static isMobile(): boolean {
    return this.getBreakpoint() === 'xs' || this.getBreakpoint() === 'sm';
  }

  static isTablet(): boolean {
    return this.getBreakpoint() === 'md';
  }

  static isDesktop(): boolean {
    return ['lg', 'xl', '2xl'].includes(this.getBreakpoint());
  }

  static useResponsiveValue<T>(values: Partial<Record<string, T>>): T {
    const breakpoint = this.getBreakpoint();
    
    // Find the most specific value for current breakpoint
    const breakpointOrder = ['2xl', 'xl', 'lg', 'md', 'sm', 'xs'];
    
    for (const bp of breakpointOrder) {
      if (breakpoint === bp && values[bp] !== undefined) {
        return values[bp]!;
      }
    }
    
    // Fallback to next smaller breakpoint
    for (const bp of breakpointOrder) {
      if (values[bp] !== undefined) {
        return values[bp]!;
      }
    }
    
    throw new Error('No responsive value provided');
  }

  static generateResponsiveClasses(
    baseClass: string,
    responsiveValues: Partial<Record<string, string>>
  ): string {
    const classes = [baseClass];
    
    Object.entries(responsiveValues).forEach(([breakpoint, value]) => {
      if (breakpoint === 'default') {
        classes.push(value);
      } else {
        classes.push(`${breakpoint}:${value}`);
      }
    });
    
    return classes.join(' ');
  }
}

Best Practices

  1. Mobile-first approach - Design for mobile first, then enhance for larger screens
  2. Consistent breakpoints - Use standard breakpoint sizes across the application
  3. Flexible grids - Use CSS Grid and Flexbox for adaptive layouts
  4. Responsive images - Optimize images for different screen sizes and resolutions
  5. Touch-friendly targets - Ensure interactive elements are appropriately sized for touch

Stop Conditions

STOP and escalate if:

  • Responsive strategy unclear or inconsistent
  • Breakpoint definitions not established
  • Mobile-first approach not defined
  • Testing strategy for responsive design missing

Skill Version: 1.0.0