tailwindcss-responsive-darkmode

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

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tailwindcss-responsive-darkmode" with this command: npx skills add josiahsiegel/claude-plugin-marketplace/josiahsiegel-claude-plugin-marketplace-tailwindcss-responsive-darkmode

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.

<!-- 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

Prefix Min Width Typical Devices CSS Media Query

(none) 0px All mobile phones All 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

@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:

<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:

@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

<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

<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

<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

<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

<!-- 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.

@plugin "@tailwindcss/container-queries";

<!-- 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

Class Min-width Use Case

@xs

20rem (320px) Small widgets

@sm

24rem (384px) Compact cards

@md

28rem (448px) Standard cards

@lg

32rem (512px) Wide cards

@xl

36rem (576px) Full-width components

@2xl

42rem (672px) Large containers

@3xl

48rem (768px) Page sections

When to Use Container vs Viewport Queries

Container Queries Viewport Queries

Reusable components Page-level layouts

Cards in various contexts Navigation bars

Sidebar widgets Hero sections

CMS/embedded content Full-width sections

Max-Width Breakpoints

Target screens below a certain size:

<!-- 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 :

@import "tailwindcss"; /* No additional configuration needed */

<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:

@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

<!-- 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

// Simple toggle function toggleDarkMode() { document.documentElement.classList.toggle('dark'); }

// With localStorage persistence function 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 load initDarkMode();

Three-Way Toggle (Light/Dark/System)

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 changes window.matchMedia('(prefers-color-scheme: dark)') .addEventListener('change', () => { if (localStorage.getItem('theme') === 'system') { applyTheme(); } });

applyTheme();

Data Attribute Strategy

@custom-variant dark (&:where([data-theme="dark"], [data-theme="dark"] *));

<html data-theme="dark"> <body> <div class="bg-white dark:bg-gray-900">Content</div> </body> </html>

Dark Mode with Next.js (next-themes)

npm install next-themes

// app/providers.tsx 'use client';

import { ThemeProvider } from 'next-themes';

export function Providers({ children }) { return ( <ThemeProvider attribute="class" defaultTheme="system"> {children} </ThemeProvider> ); }

// app/layout.tsx import { Providers } from './providers';

export default function RootLayout({ children }) { return ( <html lang="en" suppressHydrationWarning> <body> <Providers>{children}</Providers> </body> </html> ); }

// 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

<!-- 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

@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); } }

<div class="bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]"> Semantic colors </div>

Typography Plugin Dark Mode

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

Combining Responsive and Dark Mode

<!-- 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

<!-- 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">

  1. Touch-Friendly Interactive Elements

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

<!-- 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>

  1. Fluid Typography (Eliminates Breakpoint Jumps)

@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); }

<h1 class="text-fluid-xl font-bold">Smoothly Scaling Heading</h1> <p class="text-fluid-base leading-relaxed">Smoothly scaling body text.</p>

  1. Use Semantic Dark Mode Colors

@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); }

  1. Test All Breakpoints

Use the debug-screens plugin during development:

npm install -D @tailwindcss/debug-screens

@plugin "@tailwindcss/debug-screens";

  1. Reduce Repetition with Components

/* 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; } }

  1. 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

<!-- 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>

  1. Reduced Motion Preference

Respect users who prefer reduced motion:

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

  1. Performance-Optimized Responsive Images

<!-- 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" />

  1. Safe Area Handling (Notched Devices)

@utility safe-area-pb { padding-bottom: env(safe-area-inset-bottom); }

<!-- Bottom navigation respects device notch --> <nav class="fixed bottom-0 inset-x-0 safe-area-pb bg-white border-t"> Navigation </nav>

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

tailwindcss-advanced-layouts

No summary provided by upstream source.

Repository SourceNeeds Review
General

tailwindcss-animations

No summary provided by upstream source.

Repository SourceNeeds Review
General

tailwindcss-mobile-first

No summary provided by upstream source.

Repository SourceNeeds Review
General

docker-best-practices

No summary provided by upstream source.

Repository SourceNeeds Review