Toggle between light and dark mode in Storybook
—
Comprehensive configuration options for customizing Storybook Dark Mode behavior, themes, and CSS class management through Storybook parameters.
Configuration object for customizing dark mode behavior in .storybook/preview.js. Parameters are passed as a partial DarkModeStore object.
/**
* Dark mode configuration parameters
* All properties are optional and will be merged with default values
*/
type DarkModeParameters = Partial<DarkModeStore>;
interface DarkModeStore {
/** Initial theme preference - takes precedence over OS preference */
current?: 'light' | 'dark';
/** Custom dark theme configuration object */
dark?: ThemeVars;
/** Custom light theme configuration object */
light?: ThemeVars;
/** CSS class(es) applied to target elements in dark mode */
darkClass?: string | string[];
/** CSS class(es) applied to target elements in light mode */
lightClass?: string | string[];
/** CSS selector for target element in preview iframe */
classTarget?: string;
/** Whether to apply theme classes to preview iframe content */
stylePreview?: boolean;
/** Whether user has manually set a theme preference (internal) */
userHasExplicitlySetTheTheme?: boolean;
}Override default Storybook themes with custom styling.
/**
* Storybook theme configuration object
* Extends @storybook/theming ThemeVars interface
*/
interface ThemeVars {
appBg?: string;
appContentBg?: string;
appBorderColor?: string;
appBorderRadius?: number;
fontBase?: string;
fontCode?: string;
textColor?: string;
barTextColor?: string;
barSelectedColor?: string;
barBg?: string;
inputBg?: string;
inputBorder?: string;
inputTextColor?: string;
inputBorderRadius?: number;
// ... additional Storybook theme properties
}Usage Examples:
import { themes } from '@storybook/theming';
export const parameters = {
darkMode: {
// Custom dark theme
dark: {
...themes.dark,
appBg: '#1a1a1a',
appContentBg: '#2d2d2d',
textColor: '#ffffff'
},
// Custom light theme
light: {
...themes.normal,
appBg: '#f8f9fa',
appContentBg: '#ffffff',
textColor: '#333333'
}
}
};Control which theme is active when Storybook first loads.
Theme Precedence Order:
current parameter valueexport const parameters = {
darkMode: {
// Force light theme on initial load
current: 'light',
// Or force dark theme
current: 'dark'
}
};Customize CSS classes applied to manager and preview elements for theme styling.
/**
* CSS class configuration for theme styling
*/
interface ClassConfiguration {
/** Class(es) applied in dark mode - can be string or array */
darkClass?: string | string[];
/** Class(es) applied in light mode - can be string or array */
lightClass?: string | string[];
/** CSS selector for target element in preview iframe */
classTarget?: string;
}Default Values:
darkClass: ['dark']lightClass: ['light']classTarget: 'body'Usage Examples:
export const parameters = {
darkMode: {
// Single class names
darkClass: 'theme-dark',
lightClass: 'theme-light',
// Multiple classes
darkClass: ['dark', 'high-contrast'],
lightClass: ['light', 'standard-contrast'],
// Target different element
classTarget: 'html' // Apply classes to <html> instead of <body>
}
};Control whether theme classes are applied to the preview iframe content.
/**
* Preview styling configuration
*/
interface PreviewStylingConfig {
/** Whether to apply theme classes to preview iframe */
stylePreview?: boolean;
/** CSS selector for target element within preview iframe */
classTarget?: string;
}Usage Examples:
export const parameters = {
darkMode: {
// Enable preview iframe styling
stylePreview: true,
// Apply classes to specific element in preview
classTarget: '.story-wrapper'
}
};import { themes } from '@storybook/theming';
export const parameters = {
darkMode: {
// Initial theme
current: 'light',
// Custom themes
dark: {
...themes.dark,
appBg: '#0d1117',
appContentBg: '#161b22',
appBorderColor: '#30363d',
textColor: '#f0f6fc',
barTextColor: '#f0f6fc',
barSelectedColor: '#58a6ff',
barBg: '#161b22'
},
light: {
...themes.normal,
appBg: '#ffffff',
appContentBg: '#ffffff',
appBorderColor: '#e1e4e8',
textColor: '#24292f',
barTextColor: '#24292f',
barSelectedColor: '#0969da',
barBg: '#f6f8fa'
},
// CSS class configuration
darkClass: ['dark-mode', 'high-contrast'],
lightClass: ['light-mode', 'standard-contrast'],
classTarget: 'html',
// Preview iframe styling
stylePreview: true
}
};The addon automatically persists user theme preferences using localStorage with the key 'sb-addon-themes-3'. This includes:
Storage Structure:
interface StoredData {
current: 'light' | 'dark';
dark: ThemeVars;
light: ThemeVars;
classTarget: string;
darkClass: string | string[];
lightClass: string | string[];
stylePreview: boolean;
userHasExplicitlySetTheTheme: boolean;
}Install with Tessl CLI
npx tessl i tessl/npm-storybook-dark-mode