Toggle between light and dark mode in Storybook
npx @tessl/cli install tessl/npm-storybook-dark-mode@3.0.0Storybook Dark Mode is a Storybook addon that enables users to toggle between light and dark mode themes within the Storybook interface. It provides comprehensive theme customization through configuration parameters, React hooks for component integration, and programmatic theme control with localStorage persistence.
npm install --save-dev storybook-dark-modeimport { useDarkMode } from 'storybook-dark-mode';For event-based integration:
import {
DARK_MODE_EVENT_NAME,
UPDATE_DARK_MODE_EVENT_NAME
} from 'storybook-dark-mode';For advanced/internal APIs:
import { store, updateStore, prefersDark } from 'storybook-dark-mode';Add to .storybook/main.js:
module.exports = {
addons: ['storybook-dark-mode']
};Configure themes in .storybook/preview.js:
import { themes } from '@storybook/theming';
export const parameters = {
darkMode: {
// Override the default dark theme
dark: { ...themes.dark, appBg: 'black' },
// Override the default light theme
light: { ...themes.normal, appBg: 'red' },
// Set the initial theme
current: 'light'
}
};Use the hook to integrate with your components:
import React from 'react';
import { useDarkMode } from 'storybook-dark-mode';
function ThemeWrapper({ children }) {
const isDark = useDarkMode();
return (
<div className={isDark ? 'dark-theme' : 'light-theme'}>
{children}
</div>
);
}Storybook Dark Mode is built around several key components:
React hook for accessing current theme state within Storybook stories and components.
function useDarkMode(): boolean;Comprehensive configuration options for customizing themes, CSS classes, and behavior through Storybook parameters.
type DarkModeParameters = Partial<DarkModeStore>;Event system for manual theme control and integration with custom components.
const DARK_MODE_EVENT_NAME: 'DARK_MODE';
const UPDATE_DARK_MODE_EVENT_NAME: 'UPDATE_DARK_MODE';Advanced APIs for low-level theme management, store functions, and OS preference detection.
function store(userTheme?: Partial<DarkModeStore>): DarkModeStore;
function updateStore(newStore: DarkModeStore): void;
const prefersDark: MediaQueryList;type Mode = 'light' | 'dark';
interface DarkModeStore {
/** CSS selector for preview iframe target element */
classTarget: string;
/** Current active theme mode */
current: Mode;
/** Dark theme configuration object */
dark: ThemeVars;
/** CSS class(es) applied in dark mode */
darkClass: string | string[];
/** Light theme configuration object */
light: ThemeVars;
/** CSS class(es) applied in light mode */
lightClass: string | string[];
/** Whether to apply theme classes to preview iframe */
stylePreview: boolean;
/** Whether user has manually set a theme preference */
userHasExplicitlySetTheTheme: boolean;
}
/**
* Storybook theme configuration object (from @storybook/theming)
* Used to customize the appearance of the Storybook UI
*/
interface ThemeVars {
/** Main application background color */
appBg?: string;
/** Content area background color */
appContentBg?: string;
/** Border color for UI elements */
appBorderColor?: string;
/** Border radius for UI elements */
appBorderRadius?: number;
/** Base font family */
fontBase?: string;
/** Code/monospace font family */
fontCode?: string;
/** Primary text color */
textColor?: string;
/** Toolbar text color */
barTextColor?: string;
/** Selected toolbar item color */
barSelectedColor?: string;
/** Toolbar background color */
barBg?: string;
/** Input field background color */
inputBg?: string;
/** Input field border color */
inputBorder?: string;
/** Input field text color */
inputTextColor?: string;
/** Input field border radius */
inputBorderRadius?: number;
/** Brand title text */
brandTitle?: string;
/** Brand URL for logo/title links */
brandUrl?: string;
/** Brand image/logo URL */
brandImage?: string;
/** Brand target attribute for links */
brandTarget?: string;
/** Color palette */
colorPrimary?: string;
colorSecondary?: string;
/** Additional theme properties as defined by Storybook theming */
[key: string]: any;
}