Skip to content

Latest commit

 

History

History
249 lines (193 loc) · 6.45 KB

File metadata and controls

249 lines (193 loc) · 6.45 KB

Dark Theme Implementation Guide

This chat UI application includes comprehensive dark theme support built with Next.js 15, React 18, and next-themes. The implementation provides a seamless user experience with system theme detection and manual controls.

Features

  • System Theme Detection: Automatically detects and follows the user's system theme preference (default)
  • Manual Theme Toggle: Users can manually switch between light and dark themes
  • Smooth Transitions: CSS transitions provide smooth theme switching animations (0.3s ease)
  • Persistent Theme: Theme preference is saved and restored across sessions using localStorage
  • SSR Safe: Prevents hydration mismatches with proper mounting checks
  • Accessibility: Full ARIA support, screen reader compatibility, and keyboard navigation

Components

Theme Provider (components/theme-provider.tsx)

Wraps the entire application with theme context using next-themes. Configured in app/layout.tsx with:

<ThemeProvider
  attribute="class"
  defaultTheme="system"
  enableSystem
  disableTransitionOnChange
>
  {children}
</ThemeProvider>

Key Configuration:

  • attribute="class": Uses CSS classes for theme switching
  • defaultTheme="system": Follows system preference by default
  • enableSystem: Enables system theme detection
  • disableTransitionOnChange: Prevents flash during theme changes

Simple Theme Toggle (components/theme-toggle.tsx)

A minimal toggle button that switches between light and dark themes with animated sun/moon icons:

  • ☀️ Sun icon for light theme (visible in light mode)
  • 🌙 Moon icon for dark theme (visible in dark mode)
  • Smooth rotation and scale animations
  • Ghost button variant for subtle appearance

Advanced Theme Toggle Dropdown (components/theme-toggle-dropdown.tsx)

A dropdown menu that allows selection between light and dark themes:

  • Shows current theme in button label
  • Dropdown menu with explicit theme options
  • Proper hydration handling to prevent SSR mismatches
  • Accessible with proper ARIA labels

Note: The current implementation only supports light and dark themes (no system option in dropdown).

CSS Variables & Theming

The application uses CSS custom properties defined in app/globals.css for consistent theming:

Light Theme (Default)

:root {
  --background: 0 0% 100%;
  --foreground: 222.2 84% 4.9%;
  --primary: 222.2 47.4% 11.2%;
  --primary-foreground: 210 40% 98%;
  --secondary: 210 40% 96%;
  --secondary-foreground: 222.2 47.4% 11.2%;
  --muted: 210 40% 96%;
  --muted-foreground: 215.4 16.3% 46.9%;
  --accent: 210 40% 96%;
  --accent-foreground: 222.2 47.4% 11.2%;
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 210 40% 98%;
  --border: 214.3 31.8% 91.4%;
  --input: 214.3 31.8% 91.4%;
  --ring: 222.2 84% 4.9%;
  --radius: 0.5rem;
}

Dark Theme

.dark {
  --background: 222.2 84% 4.9%;
  --foreground: 210 40% 98%;
  --primary: 210 40% 98%;
  --primary-foreground: 222.2 47.4% 11.2%;
  --secondary: 217.2 32.6% 17.5%;
  --secondary-foreground: 210 40% 98%;
  --muted: 217.2 32.6% 17.5%;
  --muted-foreground: 215 20.2% 65.1%;
  --accent: 217.2 32.6% 17.5%;
  --accent-foreground: 210 40% 98%;
  --destructive: 0 62.8% 30.6%;
  --destructive-foreground: 210 40% 98%;
  --border: 217.2 32.6% 17.5%;
  --input: 217.2 32.6% 17.5%;
  --ring: 212.7 26.8% 83.9%;
}

Tailwind Configuration

Dark mode is configured in tailwind.config.js:

module.exports = {
  darkMode: ["class"], // Uses class-based dark mode
  theme: {
    extend: {
      colors: {
        background: "hsl(var(--background))",
        foreground: "hsl(var(--foreground))",
        primary: {
          DEFAULT: "hsl(var(--primary))",
          foreground: "hsl(var(--primary-foreground))",
        },
        // ... other color mappings
      },
    },
  },
  plugins: [require("tailwindcss-animate")],
};

Smooth Transitions

The application includes smooth transitions for theme changes:

body {
  @apply bg-background text-foreground;
  transition:
    background-color 0.3s ease,
    color 0.3s ease;
}

.theme-transition {
  transition:
    background-color 0.3s ease,
    color 0.3s ease,
    border-color 0.3s ease;
}

Usage

For Users

  1. System Theme (Default): Automatically follows your OS dark/light mode preference
  2. Manual Toggle: Click the theme toggle button in the chat interface
  3. Theme Persistence: Your preference is saved and restored across sessions

For Developers

import { useTheme } from "next-themes";

function MyComponent() {
  const { theme, setTheme } = useTheme();
  
  return (
    <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
      Current theme: {theme}
    </button>
  );
}

Implementation Details

Hydration Safety

The theme components handle SSR properly to prevent hydration mismatches:

const [mounted, setMounted] = React.useState(false);

React.useEffect(() => {
  setMounted(true);
}, []);

if (!mounted) {
  return <LoadingState />;
}

Theme Detection

  • System Theme: Uses prefers-color-scheme media query
  • Manual Override: Stored in localStorage as theme key
  • Class Application: Automatically applies .dark class to <html> element

Customization

Adding New Color Variables

  1. Add to both :root and .dark selectors in app/globals.css
  2. Map to Tailwind colors in tailwind.config.js
  3. Use with hsl(var(--your-variable)) format

Custom Theme Colors

:root {
  --custom-color: 210 40% 50%;
}

.dark {
  --custom-color: 210 40% 80%;
}
// tailwind.config.js
colors: {
  custom: "hsl(var(--custom-color))",
}

Accessibility Features

  • ARIA Labels: All theme controls have descriptive labels
  • Screen Reader Support: Hidden text for assistive technologies
  • Keyboard Navigation: Full keyboard accessibility support
  • High Contrast: Proper contrast ratios in both themes
  • Focus Indicators: Visible focus states for keyboard users

Package Dependencies

{
  "next-themes": "^0.4.6",
  "lucide-react": "^0.294.0",
  "@radix-ui/react-dropdown-menu": "^2.0.6"
}

Best Practices

  1. Always use CSS variables for colors that need to change between themes
  2. Test both themes during development
  3. Consider system theme as the default for better UX
  4. Use semantic color names (primary, secondary, muted) rather than specific colors
  5. Ensure proper contrast ratios for accessibility compliance