A storybook addon that lets your users toggle between dark and light mode.
Installations
npm install storybook-dark-mode
Developer
hipstersmoothie
Developer Guide
Module System
CommonJS
Min. Node Version
Typescript Support
Yes
Node Version
18.20.3
NPM Version
10.7.0
Statistics
444 Stars
434 Commits
56 Forks
7 Watching
19 Branches
35 Contributors
Updated on 27 Nov 2024
Languages
TypeScript (87.03%)
JavaScript (12.97%)
Total Downloads
Cumulative downloads
Total Downloads
35,229,671
Last day
0.4%
59,225
Compared to previous day
Last week
3.2%
305,291
Compared to previous week
Last month
11.7%
1,360,824
Compared to previous month
Last year
10%
13,224,989
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Dependencies
8
Dev Dependencies
31
storybook-dark-mode
A storybook addons that lets your users toggle between dark and light mode.
Installation
Install the following npm module:
1npm i --save-dev storybook-dark-mode
or with yarn:
1yarn add -D storybook-dark-mode
Then, add following content to .storybook/main.js
1module.exports = { 2 addons: ['storybook-dark-mode'] 3};
Upgrade from earlier version
Change in .storybook/main.js
1module.exports = { 2- addons: ['storybook-dark-mode/register'] 3+ addons: ['storybook-dark-mode'] 4};
Configuration
Configure the dark and light mode by adding the following to your .storybook/preview.js
file:
1import { themes } from '@storybook/theming'; 2 3export const parameters = { 4 darkMode: { 5 // Override the default dark theme 6 dark: { ...themes.dark, appBg: 'black' }, 7 // Override the default light theme 8 light: { ...themes.normal, appBg: 'red' } 9 } 10};
Default Theme
Order of precedence for the initial color scheme:
- If the user has previously set a color theme it's used
- The value you have configured for
current
parameter in your storybook - The OS color scheme preference
Once the initial color scheme has been set, subsequent reloads will use this value.
To clear the cached color scheme you have to localStorage.clear()
in the chrome console.
1export const parameters = { 2 darkMode: { 3 // Set the initial theme 4 current: 'light' 5 } 6};
Dark/Light Class
This plugin will apply a dark and light class name to the manager. This allows you to easily write dark mode aware theme overrides for the storybook UI.
You can override the classNames applied when switching between light and dark mode using the darkClass
and lightClass
parameters.
1export const parameters = { 2 darkMode: { 3 darkClass: 'lights-out', 4 lightClass: 'lights-on' 5 } 6};
You can also pass an array to apply multiple classes.
1export const parameters = { 2 darkMode: { 3 darkClass: ['lights-out', 'foo'], 4 lightClass: ['lights-on', 'bar'] 5 } 6};
Preview class target
This plugin will apply the dark/light class to the <body>
element of the preview iframe. This can be configured with the classTarget
parameter.
The value will be passed to a querySelector()
inside the iframe.
This is useful if the <body>
is styled according to a parent's class, in that case it can be set to html
.
1export const parameters = { 2 darkMode: { 3 classTarget: 'html' 4 } 5};
Story integration
Preview ClassName
This plugin will apply the darkClass
and lightClass
classes to the preview iframe if you turn on the stylePreview
option.
1export const parameters = { 2 darkMode: { 3 stylePreview: true 4 } 5};
React
If your components use a custom Theme provider, you can integrate it by using the provided hook.
1import { useDarkMode } from 'storybook-dark-mode'; 2import { addDecorator } from '@storybook/react'; 3 4// your theme provider 5import ThemeContext from './theme'; 6 7// create a component that uses the dark mode hook 8function ThemeWrapper(props) { 9 // render your custom theme provider 10 return ( 11 <ThemeContext.Provider value={useDarkMode() ? darkTheme : defaultTheme}> 12 {props.children} 13 </ThemeContext.Provider> 14 ); 15} 16 17export const decorators = [renderStory => <ThemeWrapper>{renderStory()}</ThemeWrapper>)];
Theme Knobs
If you want to have you UI's dark mode separate from you components' dark mode, implement this global decorator:
1import { themes } from '@storybook/theming'; 2 3// Add a global decorator that will render a dark background when the 4// "Color Scheme" knob is set to dark 5const knobDecorator = storyFn => { 6 // A knob for color scheme added to every story 7 const colorScheme = select('Color Scheme', ['light', 'dark'], 'light'); 8 9 // Hook your theme provider with some knobs 10 return React.createElement(ThemeProvider, { 11 // A knob for theme added to every story 12 theme: select('Theme', Object.keys(themes), 'default'), 13 colorScheme, 14 children: [ 15 React.createElement('style', { 16 dangerouslySetInnerHTML: { 17 __html: `html { ${ 18 colorScheme === 'dark' ? 'background-color: rgb(35,35,35);' : '' 19 } }` 20 } 21 }), 22 storyFn() 23 ] 24 }); 25}; 26 27export const decorators = [knobDecorator];
Events
You can also listen for the DARK_MODE
event via the addons channel.
1import { addons } from '@storybook/preview-api'; 2import { addDecorator } from '@storybook/react'; 3import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode'; 4 5// your theme provider 6import ThemeContext from './theme'; 7 8// get channel to listen to event emitter 9const channel = addons.getChannel(); 10 11// create a component that listens for the DARK_MODE event 12function ThemeWrapper(props) { 13 // this example uses hook but you can also use class component as well 14 const [isDark, setDark] = useState(false); 15 16 useEffect(() => { 17 // listen to DARK_MODE event 18 channel.on(DARK_MODE_EVENT_NAME, setDark); 19 return () => channel.off(DARK_MODE_EVENT_NAME, setDark); 20 }, [channel, setDark]); 21 22 // render your custom theme provider 23 return ( 24 <ThemeContext.Provider value={isDark ? darkTheme : defaultTheme}> 25 {props.children} 26 </ThemeContext.Provider> 27 ); 28} 29 30export const decorators = [renderStory => <ThemeWrapper>{renderStory()}</ThemeWrapper>)];
Since in docs mode, Storybook will not display its toolbar,
You can also trigger the UPDATE_DARK_MODE
event via the addons channel if you want to control that option in docs mode,
By editing your .storybook/preview.js
.
1import React from 'react'; 2import { addons } from '@storybook/preview-api'; 3import { DocsContainer } from '@storybook/addon-docs'; 4import { themes } from '@storybook/theming'; 5 6import { 7 DARK_MODE_EVENT_NAME, 8 UPDATE_DARK_MODE_EVENT_NAME 9} from 'storybook-dark-mode'; 10 11const channel = addons.getChannel(); 12 13export const parameters = { 14 darkMode: { 15 current: 'light', 16 dark: { ...themes.dark }, 17 light: { ...themes.light } 18 }, 19 docs: { 20 container: props => { 21 const [isDark, setDark] = React.useState(); 22 23 const onChangeHandler = () => { 24 channel.emit(UPDATE_DARK_MODE_EVENT_NAME); 25 }; 26 27 React.useEffect(() => { 28 channel.on(DARK_MODE_EVENT_NAME, setDark); 29 return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark); 30 }, [channel, setDark]); 31 32 return ( 33 <div> 34 <input type="checkbox" onChange={onChangeHandler} /> 35 <DocsContainer {...props} /> 36 </div> 37 ); 38 } 39 } 40};
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
No vulnerabilities found.
Reason
no dangerous workflow patterns detected
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
Found 4/14 approved changesets -- score normalized to 2
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
dependency not pinned by hash detected -- score normalized to 0
Details
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/push.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/hipstersmoothie/storybook-dark-mode/push.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/push.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/hipstersmoothie/storybook-dark-mode/push.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/hipstersmoothie/storybook-dark-mode/release.yml/master?enable=pin
- Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/hipstersmoothie/storybook-dark-mode/release.yml/master?enable=pin
- Info: 0 out of 4 GitHub-owned GitHubAction dependencies pinned
Reason
detected GitHub workflow tokens with excessive permissions
Details
- Warn: no topLevel permission defined: .github/workflows/push.yml:1
- Warn: no topLevel permission defined: .github/workflows/release.yml:1
- Info: no jobLevel write permissions found
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 20 are checked with a SAST tool
Reason
26 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw
- Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c
- Warn: Project is vulnerable to: GHSA-ghr5-ch3p-vcr6
- Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc
- Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx
- Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6
- Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m / GHSA-xvch-5gv4-984h
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-gcx4-mw62-g8wm
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg
- Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p
- Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36
- Warn: Project is vulnerable to: GHSA-8jhw-289h-jh2g
- Warn: Project is vulnerable to: GHSA-64vr-g452-qvp3
- Warn: Project is vulnerable to: GHSA-9cwx-2883-4wfx
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
Score
2.7
/10
Last Scanned on 2024-11-18
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn MoreOther packages similar to storybook-dark-mode
@styled/storybook-dark-mode
Fork of storybook-dark-mode that fixes applying the appropriate classes when viewing a story in a new window iframe.
storybook-tailwind-dark-mode
Toggle stories between light and dark mode using tailwind
@csstools/postcss-light-dark-function
Use the light-dark() color function in CSS
@primer/primitives
Typography, spacing, and color primitives for Primer design system