Theme Switch
The Theme Switch component provides an elegant toggle for switching between light and dark themes. It automatically detects system preferences and persists user choices across sessions.
When to use
- To provide theme switching functionality in your application
- When supporting both light and dark modes
- To respect user system preferences
- For improved accessibility and user experience
Features
- Automatic system preference detection
- LocalStorage persistence
- Smooth animations
- Multiple size variants
- Accessible keyboard navigation
- Works with any framework
- Flicker prevention solution included
Without proper setup, pages may briefly flash light mode before switching to dark mode on refresh. See the "Preventing Dark Mode Flicker" section in the Usage tab for the solution.
Anatomy
- Switch Button: The clickable toggle control
- Thumb: Moving indicator showing current state
- Icons: Sun (light) and moon (dark) icons
- Label: Optional text label
Basic Usage (Uncontrolled)
This toggle manages its own state and applies theme to the document automatically.
Size Variants
Available in small, medium (default), and large sizes.
Fixed/Floating Variants
Header Integration Example
How the theme toggle looks in a typical application header.
My Application
Keyboard Navigation Test
Try using Tab to focus and Enter/Space to toggle these switches:
Use Tab to navigate between toggles, then press Enter or Space to activate them.
Disabled State
No Hover Effect
Installation
npm install @pm7/core
CSS Classes
Class | Description |
---|---|
Base Classes | |
pm7-theme-switch |
Base class for theme switch container |
pm7-theme-switch-button |
The toggle button (auto-created) |
pm7-theme-switch-thumb |
The moving thumb indicator (auto-created) |
pm7-theme-switch-icon |
Icon container (auto-created) |
Size Modifiers | |
pm7-theme-switch--sm |
Small size variant |
pm7-theme-switch--lg |
Large size variant |
State Modifiers | |
pm7-theme-switch--disabled |
Disabled state |
pm7-theme-switch--no-hover |
Removes hover effects |
Layout Modifiers | |
pm7-theme-switch--label-start |
Places label before the switch |
Position Modifiers | |
pm7-theme-switch--fixed |
Fixed position (bottom right) with label |
pm7-theme-switch--fixed-icon |
Fixed position circular button (icon only) |
Data Attributes
Attribute | Type | Default | Description |
---|---|---|---|
data-pm7-theme-switch |
boolean | - | Marks element for auto-initialization |
data-theme |
string | 'light' | Current theme state (auto-managed) |
data-default-theme |
string | null | Override default theme ('light' or 'dark'). Maps to defaultTheme option. |
data-storage-key |
string | 'pm7-theme' | LocalStorage key for persistence. Maps to storageKey option. |
data-apply-to-root |
boolean | true | Apply 'dark' class to document root. Maps to applyToRoot option. |
Basic Usage
<!-- Basic theme switch -->
<div class="pm7-theme-switch" data-pm7-theme-switch>
<span>Theme</span>
</div>
<!-- Without label -->
<div class="pm7-theme-switch" data-pm7-theme-switch></div>
<!-- Small size (use CSS class, not data attribute) -->
<div class="pm7-theme-switch pm7-theme-switch--sm" data-pm7-theme-switch>
<span>Dark mode</span>
</div>
Auto-initialization
Theme Switch components with the data-pm7-theme-switch
attribute are automatically initialized when the DOM loads. This means you don't need to write any JavaScript for basic usage.
<!-- This will auto-initialize on page load -->
<div class="pm7-theme-switch" data-pm7-theme-switch></div>
<!-- Prevent auto-initialization if you want manual control -->
<div class="pm7-theme-switch my-custom-switch"></div>
<script>
// Manually initialize later
const element = document.querySelector('.my-custom-switch');
new PM7ThemeSwitch(element, { /* options */ });
</script>
React Example
function App() {
return (
<div className="pm7-theme-switch" data-pm7-theme-switch>
<span>Theme</span>
</div>
);
}
Vue Example
<template>
<div class="pm7-theme-switch" data-pm7-theme-switch>
<span>Theme</span>
</div>
</template>
JavaScript API
import { PM7ThemeSwitch } from '@pm7/core';
// Manual initialization with all options
const element = document.querySelector('.my-theme-switch');
const themeSwitch = new PM7ThemeSwitch(element, {
defaultTheme: 'dark', // 'light', 'dark', or null for auto-detect
storageKey: 'pm7-theme', // LocalStorage key for persistence
applyToRoot: true, // Apply 'dark' class to document root
onChange: (theme) => { // Called on user interaction only
console.log('Theme changed to:', theme);
}
});
// Methods
themeSwitch.setTheme('dark'); // Set theme programmatically
themeSwitch.getTheme(); // Get current theme
themeSwitch.toggle(); // Toggle theme
// Static method for auto-initialization
PM7ThemeSwitch.autoInit(); // Initialize all [data-pm7-theme-switch] elements
Custom Storage Key
<!-- Use a custom localStorage key -->
<div class="pm7-theme-switch"
data-pm7-theme-switch
data-storage-key="my-app-theme">
</div>
Without Root Class Application
<!-- Don't apply 'dark' class to document root -->
<div class="pm7-theme-switch"
data-pm7-theme-switch
data-apply-to-root="false">
</div>
Preventing Dark Mode Flicker
When implementing dark mode, users may experience a "flicker" where the page briefly shows in light mode before switching to dark mode on refresh. To prevent this, add the following script in your HTML <head>
before any stylesheets:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Your App</title>
<!-- Dark mode flicker prevention - MUST come before stylesheets -->
<script>
// Prevent dark mode flicker - must run before page renders
(function() {
const savedTheme = localStorage.getItem('pm7-theme');
if (savedTheme === 'dark' || (!savedTheme && window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
})();
</script>
<!-- Your stylesheets come AFTER the script -->
<link rel="stylesheet" href="@pm7/core/styles/index.css">
<link rel="stylesheet" href="your-styles.css">
</head>
Why this works: The script runs synchronously before the browser starts rendering, applying the dark class immediately if needed. This eliminates the visual flicker that occurs when dark mode is applied after the page loads.
Important Notes
- The
onChange
callback is only triggered by user interaction, not during initial theme setup - Size variants must be applied using CSS classes (e.g.,
pm7-theme-switch--sm
), not data attributes - Components are automatically initialized on page load if they have the
data-pm7-theme-switch
attribute - The component automatically detects and respects system theme preferences
- Theme preference is persisted in localStorage and survives page reloads
- Prevent flicker: Add the flicker prevention script (see above) to your HTML
<head>
to avoid light mode flash on page refresh
Accessibility
The Theme Switch component is fully accessible:
- Keyboard navigable with Tab key
- Toggleable with Space or Enter keys
- ARIA attributes for screen readers
- Proper role and state announcements
- Respects prefers-reduced-motion
Copy this link to share the Theme Switch documentation with AI assistants:
🤖 AI-Optimized Documentation
The documentation link above provides AI assistants with complete context about the Theme Switch component, including all props, methods, examples, and best practices.
Tip: When asking AI assistants to help implement the Theme Switch, include this documentation link for accurate, up-to-date information about the component API.