Tailwindcss Responsive Darkmode

by josiahsiegel5a1b1123b9e5No license58 starsListed Oct 8, 2026Updated Oct 8, 2026Repository updated 3 months ago

Tailwind CSS responsive design and dark mode patterns (2025-2026). PROACTIVELY activate for: (1) dark mode setup (class-based vs media-query, dark: variant), (2) toggling dark mode at runtime (data-theme, html.dark), (3) prefers-color-scheme handling, (4) per-component dark variants, (5) responsive design with dark mode (combining sm:dark:bg-*), (6) system / light / dark / high-contrast theming, (7) CSS color-scheme property, (8) avoiding flash of unstyled content (FOUC) in dark mode, (9) dark-mode color tokens via @theme. Provides: dark-mode toggle implementation, FOUC prevention pattern, color-token templates, and system-preference detection.

AI-generated overview

Reference guidance for Tailwind CSS responsive breakpoints, container queries, and dark mode theming patterns.

What it does
This skill supplies reference documentation on Tailwind CSS responsive design and dark mode, covering mobile-first breakpoints, custom and content-driven breakpoints, container queries, and max-width queries. It also documents dark mode strategies such as media-query, class selector, and data-attribute approaches, plus JavaScript toggles, color tokens, and FOUC prevention. It produces code snippets and configuration examples rather than running any tooling.
When to use it
Use it when implementing or reviewing responsive layouts and dark mode in a Tailwind CSS project. It fits tasks like setting up a theme toggle, defining breakpoints, or combining responsive and dark variants.
Requirements
No scripts or runtime are included; it is instructions and reference material only. Applying the examples assumes a project using Tailwind CSS, and some snippets reference optional packages such as next-themes, @tailwindcss/container-queries, and @tailwindcss/debug-screens.

Tailwind CSS Responsive Design & Dark Mode (2025/2026)

Responsive Design

Mobile-First Approach (Industry Standard 2025/2026)

Tailwind uses a mobile-first breakpoint system. With over 60% of global web traffic from mobile devices and Google's mobile-first indexing, this approach is essential.

Key Principle: Unprefixed utilities apply to ALL screen sizes. Breakpoint prefixes apply at that size AND ABOVE.

html
<!-- CORRECT: Mobile-first (progressive enhancement) --><div class="text-sm md:text-base lg:text-lg">...</div>
<!-- INCORRECT: Desktop-first thinking --><div class="lg:text-lg md:text-base text-sm">...</div>

Default Breakpoints

PrefixMin WidthTypical DevicesCSS Media Query
(none)0pxAll mobile phonesAll sizes
sm:640px (40rem)Large phones, small tablets@media (min-width: 640px)
md:768px (48rem)Tablets (portrait)@media (min-width: 768px)
lg:1024px (64rem)Tablets (landscape), laptops@media (min-width: 1024px)
xl:1280px (80rem)Desktops@media (min-width: 1280px)
2xl:1536px (96rem)Large desktops@media (min-width: 1536px)

2025/2026 Device Coverage

Common device sizes to test:

  • 320px: Older iPhones, smallest supported
  • 375px: Modern iPhone base (~17% of mobile)
  • 390-430px: Modern large phones (~35% of mobile)
  • 768px: iPad portrait
  • 1024px: iPad landscape, laptops
  • 1280px: Standard laptops/desktops
  • 1440px: Large desktops
  • 1920px: Full HD displays

Custom Breakpoints

css
@theme {  /* Add custom breakpoints for specific content needs */  --breakpoint-xs: 20rem;   /* 320px - very small devices */  --breakpoint-3xl: 100rem; /* 1600px */  --breakpoint-4xl: 120rem; /* 1920px - full HD */
  /* Override existing breakpoints based on YOUR content */  --breakpoint-sm: 36rem;   /* 576px - when content needs space */  --breakpoint-lg: 62rem;   /* 992px - common content width */}

Usage:

html
<div class="grid xs:grid-cols-2 3xl:grid-cols-6">  <!-- Custom breakpoints work like built-in ones --></div>

Content-Driven Breakpoints (2025 Best Practice)

Instead of targeting devices, let your content determine breakpoints:

css
@theme {  /* Based on content needs, not device specs */  --breakpoint-prose: 65ch;  /* Optimal reading width */  --breakpoint-content: 75rem; /* Main content max */}

Test your design at various widths and add breakpoints where layout breaks.

Responsive Examples

Responsive Grid
html
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">  <div>Item 1</div>  <div>Item 2</div>  <div>Item 3</div>  <div>Item 4</div></div>
Responsive Typography
html
<h1 class="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">  Responsive Heading</h1>
<p class="text-sm md:text-base lg:text-lg leading-relaxed">  Responsive paragraph text</p>
Responsive Spacing
html
<section class="py-8 md:py-12 lg:py-16 px-4 md:px-8 lg:px-12">  <div class="max-w-4xl mx-auto">    Content with responsive padding  </div></section>
Responsive Navigation
html
<nav class="flex flex-col md:flex-row items-center justify-between">  <div class="hidden md:flex gap-4">    <!-- Desktop navigation -->  </div>  <button class="md:hidden">    <!-- Mobile menu button -->  </button></nav>
Show/Hide Based on Screen Size
html
<!-- Hidden on mobile, visible on desktop --><div class="hidden md:block">Desktop only</div>
<!-- Visible on mobile, hidden on desktop --><div class="block md:hidden">Mobile only</div>
<!-- Different content per breakpoint --><span class="sm:hidden">XS</span><span class="hidden sm:inline md:hidden">SM</span><span class="hidden md:inline lg:hidden">MD</span><span class="hidden lg:inline xl:hidden">LG</span><span class="hidden xl:inline 2xl:hidden">XL</span><span class="hidden 2xl:inline">2XL</span>

Container Queries (v4) - 2025 Game-Changer

Container queries enable component-level responsiveness, independent of viewport size. This is essential for reusable components in 2025.

css
@plugin "@tailwindcss/container-queries";
html
<!-- Mark parent as a query container --><div class="@container">  <div class="flex flex-col @md:flex-row @lg:gap-8">    <!-- Responds to container size, not viewport -->  </div></div>
<!-- Named containers for multiple contexts --><div class="@container/card">  <div class="@lg/card:grid-cols-2 grid grid-cols-1">    <!-- Responds specifically to 'card' container -->  </div></div>

Container Query Breakpoints

ClassMin-widthUse Case
@xs20rem (320px)Small widgets
@sm24rem (384px)Compact cards
@md28rem (448px)Standard cards
@lg32rem (512px)Wide cards
@xl36rem (576px)Full-width components
@2xl42rem (672px)Large containers
@3xl48rem (768px)Page sections

When to Use Container vs Viewport Queries

Container QueriesViewport Queries
Reusable componentsPage-level layouts
Cards in various contextsNavigation bars
Sidebar widgetsHero sections
CMS/embedded contentFull-width sections

Max-Width Breakpoints

Target screens below a certain size:

html
<!-- Only on screens smaller than md (< 768px) --><div class="md:hidden">Small screens only</div>
<!-- Custom max-width media query --><div class="[@media(max-width:600px)]:text-sm">  Custom max-width</div>

Dark Mode

Strategy: Media (Default)

Dark mode follows the user's operating system preference using prefers-color-scheme:

css
@import "tailwindcss";/* No additional configuration needed */
html
<div class="bg-white dark:bg-gray-900">  <h1 class="text-gray-900 dark:text-white">Title</h1>  <p class="text-gray-600 dark:text-gray-300">Content</p></div>

Strategy: Selector (Manual Toggle)

Control dark mode with a CSS class:

css
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
html
<!-- Add .dark class to html or body to enable dark mode --><html class="dark">  <body>    <div class="bg-white dark:bg-gray-900">      Content    </div>  </body></html>

JavaScript Toggle

javascript
// Simple togglefunction toggleDarkMode() {  document.documentElement.classList.toggle('dark');}
// With localStorage persistencefunction initDarkMode() {  const isDark = localStorage.getItem('darkMode') === 'true' ||    (!localStorage.getItem('darkMode') &&     window.matchMedia('(prefers-color-scheme: dark)').matches);
  document.documentElement.classList.toggle('dark', isDark);}
function toggleDarkMode() {  const isDark = document.documentElement.classList.toggle('dark');  localStorage.setItem('darkMode', isDark);}
// Initialize on page loadinitDarkMode();

Three-Way Toggle (Light/Dark/System)

javascript
const themes = ['light', 'dark', 'system'];
function setTheme(theme) {  localStorage.setItem('theme', theme);  applyTheme();}
function applyTheme() {  const theme = localStorage.getItem('theme') || 'system';  const isDark = theme === 'dark' ||    (theme === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches);
  document.documentElement.classList.toggle('dark', isDark);}
// Listen for system preference changeswindow.matchMedia('(prefers-color-scheme: dark)')  .addEventListener('change', () => {    if (localStorage.getItem('theme') === 'system') {      applyTheme();    }  });
applyTheme();

Data Attribute Strategy

css
@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));
html
<html data-theme="dark">  <body>    <div class="bg-white dark:bg-gray-900">Content</div>  </body></html>

Dark Mode with Next.js (next-themes)

bash
npm install next-themes
jsx
// app/providers.tsx'use client';
import { ThemeProvider } from 'next-themes';
export function Providers({ children }) {  return (    <ThemeProvider attribute="class" defaultTheme="system">      {children}    </ThemeProvider>  );}
jsx
// app/layout.tsximport { Providers } from './providers';
export default function RootLayout({ children }) {  return (    <html lang="en" suppressHydrationWarning>      <body>        <Providers>{children}</Providers>      </body>    </html>  );}
jsx
// components/ThemeToggle.tsx'use client';
import { useTheme } from 'next-themes';
export function ThemeToggle() {  const { theme, setTheme } = useTheme();
  return (    <button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>      Toggle Theme    </button>  );}

Dark Mode Color Palette

html
<!-- Text colors --><p class="text-gray-900 dark:text-gray-100">Primary text</p><p class="text-gray-600 dark:text-gray-400">Secondary text</p><p class="text-gray-400 dark:text-gray-500">Muted text</p>
<!-- Background colors --><div class="bg-white dark:bg-gray-900">Page background</div><div class="bg-gray-50 dark:bg-gray-800">Card background</div><div class="bg-gray-100 dark:bg-gray-700">Elevated background</div>
<!-- Border colors --><div class="border border-gray-200 dark:border-gray-700">Bordered element</div>
<!-- Interactive elements --><button class="bg-blue-500 hover:bg-blue-600 dark:bg-blue-600 dark:hover:bg-blue-700">  Button</button>

Dark Mode with CSS Variables

css
@theme {  /* Light mode colors (default) */  --color-bg-primary: oklch(1 0 0);  --color-bg-secondary: oklch(0.98 0 0);  --color-text-primary: oklch(0.15 0 0);  --color-text-secondary: oklch(0.4 0 0);}
/* Dark mode overrides */@media (prefers-color-scheme: dark) {  :root {    --color-bg-primary: oklch(0.15 0 0);    --color-bg-secondary: oklch(0.2 0 0);    --color-text-primary: oklch(0.95 0 0);    --color-text-secondary: oklch(0.7 0 0);  }}
html
<div class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]">  Semantic colors</div>

Typography Plugin Dark Mode

html
<article class="prose dark:prose-invert">  <!-- Markdown content automatically adapts to dark mode --></article>

Combining Responsive and Dark Mode

html
<!-- Different layouts AND colors based on screen size and theme --><div class="  grid grid-cols-1 md:grid-cols-2  bg-white dark:bg-gray-900  p-4 md:p-8  text-gray-900 dark:text-white">  <div class="hidden dark:md:block">    Only visible on md+ screens in dark mode  </div></div>

Best Practices (2025/2026)

1. Start Mobile, Then Enhance

html
<!-- CORRECT: Mobile-first progression --><div class="text-sm md:text-base lg:text-lg">
<!-- WRONG: Desktop-first thinking (more code, more bugs) --><div class="lg:text-lg md:text-base text-sm">

2. Touch-Friendly Interactive Elements

WCAG 2.2 requires 24x24px minimum, but 44x44px is recommended:

html
<!-- Touch-friendly button (44px minimum) --><button class="min-h-11 min-w-11 px-4 py-2.5">  Click me</button>
<!-- Touch-friendly navigation link --><a href="#" class="block py-3 px-4 min-h-11">  Navigation Item</a>
<!-- Adequate spacing between touch targets --><div class="flex gap-3">  <button class="min-h-11 px-4 py-2">Button 1</button>  <button class="min-h-11 px-4 py-2">Button 2</button></div>

3. Fluid Typography (Eliminates Breakpoint Jumps)

css
@theme {  --text-fluid-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);  --text-fluid-lg: clamp(1.25rem, 1rem + 1.25vw, 2rem);  --text-fluid-xl: clamp(1.5rem, 1rem + 2.5vw, 3rem);}
html
<h1 class="text-fluid-xl font-bold">Smoothly Scaling Heading</h1><p class="text-fluid-base leading-relaxed">Smoothly scaling body text.</p>

2. Use Semantic Dark Mode Colors

css
@theme {  /* Instead of raw colors, use semantic names */  --color-surface: oklch(1 0 0);  --color-surface-dark: oklch(0.15 0 0);  --color-on-surface: oklch(0.1 0 0);  --color-on-surface-dark: oklch(0.95 0 0);}

3. Test All Breakpoints

Use the debug-screens plugin during development:

bash
npm install -D @tailwindcss/debug-screens
css
@plugin "@tailwindcss/debug-screens";

4. Reduce Repetition with Components

css
/* components.css */@layer components {  .card {    @apply bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm;  }
  .section {    @apply py-12 md:py-16 lg:py-24;  }}

5. Consider Color Contrast

Ensure sufficient contrast in both light and dark modes (WCAG 2.2):

  • Normal text: 4.5:1 contrast ratio minimum
  • Large text (18pt+): 3:1 contrast ratio minimum
  • Interactive elements: 3:1 against adjacent colors
html
<!-- Good contrast in both modes --><button class="  bg-blue-600 text-white  dark:bg-blue-500 dark:text-white  hover:bg-blue-700 dark:hover:bg-blue-400  /* Focus ring for accessibility */  focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">  Action</button>

6. Reduced Motion Preference

Respect users who prefer reduced motion:

html
<div class="  transition-transform duration-300  hover:scale-105  motion-reduce:transition-none  motion-reduce:hover:scale-100">  Respects motion preferences</div>

7. Performance-Optimized Responsive Images

html
<!-- Lazy load below-fold images --><img  src="image.jpg"  alt="Description"  loading="lazy"  class="w-full h-auto"/>
<!-- Responsive srcset --><img  src="medium.jpg"  srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1200w"  sizes="(min-width: 1024px) 50vw, 100vw"  alt="Responsive image"  loading="lazy"  class="w-full h-auto"/>

8. Safe Area Handling (Notched Devices)

css
@utility safe-area-pb {  padding-bottom: env(safe-area-inset-bottom);}
html
<!-- Bottom navigation respects device notch --><nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t">  Navigation</nav>

Source and attribution

Source:josiahsiegel/claude-plugin-marketplaceinplugins/tailwindcss-master/skills/tailwindcss-responsive-darkmodeat commit5a1b112

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal