Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

storybook-dark-mode

hipstersmoothie885.3kMIT4.0.2TypeScript support: included

Toggle between light and dark mode in Storybook

storybook-addons, appearance

readme

storybook-dark-mode

A storybook addons that lets your users toggle between dark and light mode.

Example

Installation

Install the following npm module:

npm i --save-dev storybook-dark-mode

or with yarn:

yarn add -D storybook-dark-mode

Then, add following content to .storybook/main.js

module.exports = {
  addons: ['storybook-dark-mode']
};

Upgrade from earlier version

Change in .storybook/main.js

module.exports = {
-  addons: ['storybook-dark-mode/register']
+  addons: ['storybook-dark-mode']
};

Configuration

Configure the dark and light mode by adding the following to your .storybook/preview.js file:

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' }
  }
};

Default Theme

Order of precedence for the initial color scheme:

  1. If the user has previously set a color theme it's used
  2. The value you have configured for current parameter in your storybook
  3. 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.

export const parameters = {
  darkMode: {
    // Set the initial theme
    current: 'light'
  }
};

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.

export const parameters = {
  darkMode: {
    darkClass: 'lights-out',
    lightClass: 'lights-on'
  }
};

You can also pass an array to apply multiple classes.

export const parameters = {
  darkMode: {
    darkClass: ['lights-out', 'foo'],
    lightClass: ['lights-on', 'bar']
  }
};

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.

export const parameters = {
  darkMode: {
    classTarget: 'html'
  }
};

Story integration

Preview ClassName

This plugin will apply the darkClass and lightClass classes to the preview iframe if you turn on the stylePreview option.

export const parameters = {
  darkMode: {
    stylePreview: true
  }
};

React

If your components use a custom Theme provider, you can integrate it by using the provided hook.

import { useDarkMode } from 'storybook-dark-mode';
import { addDecorator } from '@storybook/react';

// your theme provider
import ThemeContext from './theme';

// create a component that uses the dark mode hook
function ThemeWrapper(props) {
  // render your custom theme provider
  return (
    <ThemeContext.Provider value={useDarkMode() ? darkTheme : defaultTheme}>
      {props.children}
    </ThemeContext.Provider>
  );
}

export 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:

import { themes } from '@storybook/theming';

// Add a global decorator that will render a dark background when the
// "Color Scheme" knob is set to dark
const knobDecorator = storyFn => {
  // A knob for color scheme added to every story
  const colorScheme = select('Color Scheme', ['light', 'dark'], 'light');

  // Hook your theme provider with some knobs
  return React.createElement(ThemeProvider, {
    // A knob for theme added to every story
    theme: select('Theme', Object.keys(themes), 'default'),
    colorScheme,
    children: [
      React.createElement('style', {
        dangerouslySetInnerHTML: {
          __html: `html { ${
            colorScheme === 'dark' ? 'background-color: rgb(35,35,35);' : ''
          } }`
        }
      }),
      storyFn()
    ]
  });
};

export const decorators = [knobDecorator];

Events

You can also listen for the DARK_MODE event via the addons channel.

import { addons } from '@storybook/preview-api';
import { addDecorator } from '@storybook/react';
import { DARK_MODE_EVENT_NAME } from 'storybook-dark-mode';

// your theme provider
import ThemeContext from './theme';

// get channel to listen to event emitter
const channel = addons.getChannel();

// create a component that listens for the DARK_MODE event
function ThemeWrapper(props) {
  // this example uses hook but you can also use class component as well
  const [isDark, setDark] = useState(false);

  useEffect(() => {
    // listen to DARK_MODE event
    channel.on(DARK_MODE_EVENT_NAME, setDark);
    return () => channel.off(DARK_MODE_EVENT_NAME, setDark);
  }, [channel, setDark]);

  // render your custom theme provider
  return (
    <ThemeContext.Provider value={isDark ? darkTheme : defaultTheme}>
      {props.children}
    </ThemeContext.Provider>
  );
}

export 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.

import React from 'react';
import { addons } from '@storybook/preview-api';
import { DocsContainer } from '@storybook/addon-docs';
import { themes } from '@storybook/theming';

import {
  DARK_MODE_EVENT_NAME,
  UPDATE_DARK_MODE_EVENT_NAME
} from 'storybook-dark-mode';

const channel = addons.getChannel();

export const parameters = {
  darkMode: {
    current: 'light',
    dark: { ...themes.dark },
    light: { ...themes.light }
  },
  docs: {
    container: props => {
      const [isDark, setDark] = React.useState();

      const onChangeHandler = () => {
        channel.emit(UPDATE_DARK_MODE_EVENT_NAME);
      };

      React.useEffect(() => {
        channel.on(DARK_MODE_EVENT_NAME, setDark);
        return () => channel.removeListener(DARK_MODE_EVENT_NAME, setDark);
      }, [channel, setDark]);

      return (
        <div>
          <input type="checkbox" onChange={onChangeHandler} />
          <DocsContainer {...props} />
        </div>
      );
    }
  }
};

Contributors ✨

Thanks goes to these wonderful people (emoji key):


Andrew Lisowski

💬 💻 🎨 📖 🤔 🚇 🚧 💡

Erik Hughes

💻

Adam Jahnke

💻

Carles Núñez

💻

Adam Dierkens

💻

Tobias Skarhed

💻 📖

Fatih Kalifa

💻

Jacob Coughenour

💻

Jeroen Zwartepoorte

📖 💻

Alex Khomenko

💻

Paul Fasola

📖

Pavel Keyzik

📖

David Richolm

📖 💻

Klaus Nygård

💻

Arturo Silva

📖 💻

Nikki Pantony

📖 💻

Ian VanSchooten

💻

Fabien

📖 💻

nilscox

💻

Jack Westbrook

💻

Ryan McHenry

📖 💻

Clay Risser

📖 💻

Beltrán Rengifo

💻

erik-d

📖

Christopher Dura

📖 💻

An Dang

💻

Zeno Jiricek

💻

Steven Sacks

📖 🚇 💻

Rohan Poojary

📖 🚇 💻

Lauri Luotola

💡 💻

Adam Gołąb

💻

This project follows the all-contributors specification. Contributions of any kind welcome!

changelog

v4.0.2 (Wed Jun 19 2024)

🐛 Bug Fix

  • Fix for the "Storybook preview hooks can only be called inside decorators and story functions." error #279 (@adam-golab)

Authors: 1


v4.0.1 (Mon Mar 18 2024)

:tada: This release contains work from a new contributor! :tada:

Thank you, Lauri Luotola (@leiit), for all your work!

🐛 Bug Fix

  • Fix useDarkMode to use correct channel #266 (@leiit)

🔩 Dependency Updates

Authors: 2


v4.0.0 (Fri Mar 15 2024)

:tada: This release contains work from new contributors! :tada:

Thanks for all your work!

:heart: Sergey Kozlov (@dartess)

:heart: Rohan Poojary (@RohanPoojary1107)

💥 Breaking Change

⚠️ Pushed to master

📝 Documentation

Authors: 3


v3.0.3 (Sun Nov 26 2023)

:tada: This release contains work from a new contributor! :tada:

Thank you, Steven Sacks (@stevensacks), for all your work!

🐛 Bug Fix

Authors: 2


v3.0.2 (Sun Nov 26 2023)

🐛 Bug Fix

Authors: 1


v3.0.1 (Fri Jul 28 2023)

⚠️ Pushed to master

Authors: 1


v3.0.0 (Mon Apr 03 2023)

:tada: This release contains work from new contributors! :tada:

Thanks for all your work!

:heart: Himself65 (@Himself65)

:heart: Zeno Jiricek (@airtonix)

💥 Breaking Change

🐛 Bug Fix

  • fix: use classTarget when updating manager too #223 (@airtonix)

Authors: 2


v2.1.1 (Tue Feb 21 2023)

:tada: This release contains work from a new contributor! :tada:

Thank you, An Dang (@zyzo), for all your work!

🐛 Bug Fix

Authors: 1


v2.1.0 (Sun Feb 19 2023)

🚀 Enhancement

  • feat: Add ability to toggle multiple light/dark classes #220 (@chris-dura)

Authors: 1


v2.0.6 (Fri Feb 10 2023)

:tada: This release contains work from new contributors! :tada:

Thanks for all your work!

:heart: Slava Kostenko (@Namielusi)

:heart: null@erik-d

🐛 Bug Fix

Authors: 2


v2.0.5 (Thu Dec 29 2022)

:tada: This release contains work from a new contributor! :tada:

Thank you, Beltrán Rengifo (@beltranrengifo), for all your work!

🐛 Bug Fix

🔩 Dependency Updates

Authors: 2


v2.0.4 (Tue Dec 06 2022)

🐛 Bug Fix

Authors: 1


v2.0.3 (Mon Dec 05 2022)

🐛 Bug Fix

  • don't show light/dark as a toggle since that doesn't really make any sense #199 (@hipstersmoothie)

Authors: 1


v2.0.2 (Mon Dec 05 2022)

🐛 Bug Fix

Authors: 1


v2.0.1 (Mon Dec 05 2022)

:tada: This release contains work from a new contributor! :tada:

Thank you, Clay Risser (@clayrisser), for all your work!

🐛 Bug Fix

Authors: 2


v2.0.0 (Mon Dec 05 2022)

💥 Breaking Change

  • Fix: Storybook 6.5.x Yarn PnP preset loading issue #191 (@jackw)

Authors: 1


v1.1.2 (Wed Sep 14 2022)

:tada: This release contains work from a new contributor! :tada:

Thank you, Ryan McHenry (@Develonaut), for all your work!

🐛 Bug Fix

Authors: 1


v1.1.1 (Wed Sep 14 2022)

:tada: This release contains work from new contributors! :tada:

Thanks for all your work!

:heart: nilscox (@nilscox)

:heart: Jack Westbrook (@jackw)

🐛 Bug Fix

  • Remove @storybook/* dependencies from peer dependencies #186 (@nilscox)
  • Fix: Storybook preset loading error #187 (@jackw)

Authors: 2


v1.1.0 (Wed Apr 27 2022)

:tada: This release contains work from a new contributor! :tada:

Thank you, Fabien (@frassinier), for all your work!

🚀 Enhancement

Authors: 1


v1.0.9 (Thu Feb 17 2022)

:tada: This release contains work from new contributors! :tada:

Thanks for all your work!

:heart: Arturo Silva (@artmsilva)

:heart: Nikki Pantony (@nikkipantony)

:heart: Ian VanSchooten (@IanVS)

🐛 Bug Fix

Authors: 3


v1.0.8 (Sat May 08 2021)

:tada: This release contains work from a new contributor! :tada:

Thank you, Klaus Nygård (@nygardk), for all your work!

🐛 Bug Fix

  • Fix storybook peerDependencies semver range #149 (@nygardk)

Authors: 1


v1.0.7 (Wed Mar 10 2021)

:tada: This release contains work from a new contributor! :tada:

Thank you, David Richolm (@dricholm), for all your work!

🐛 Bug Fix

  • Add parameter for classTarget to toggle iframe preview class #144 (@dricholm)

Authors: 1


v1.0.6 (Mon Mar 08 2021)

⚠️ Pushed to master

Authors: 1


v1.0.5 (Mon Mar 08 2021)

:tada: This release contains work from new contributors! :tada:

Thanks for all your work!

:heart: Paul Fasola (@PaulFasola)

:heart: Pavel Keyzik (@pavelkeyzik)

🐛 Bug Fix

  • Fix "color function invalid arg" issue when upgrading between versions of storybook #142 (@hipstersmoothie)

📝 Documentation

Authors: 3


v1.0.4 (Tue Dec 15 2020)

🐛 Bug Fix

📝 Documentation

Authors: 1


v1.0.3 (Fri Sep 11 2020)

🐛 Bug Fix

Authors: 1


v1.0.2 (Wed Sep 02 2020)

🐛 Bug Fix

Authors: 1


v1.0.1 (Wed Sep 02 2020)

🐛 Bug Fix

Authors: 1


v1.0.0 (Wed Aug 12 2020)

💥 Breaking Change

Authors: 1


v0.6.1 (Fri May 22 2020)

:tada: This release contains work from a new contributor! :tada:

Thank you, Alex Khomenko (@Clarity-89), for all your work!

🐛 Bug Fix

  • useDarkMode: read default isDark value from local storage #110 (@Clarity-89)

Authors: 1


v0.6.0 (Wed May 20 2020)

🚀 Enhancement

Authors: 1


v0.5.0 (Wed May 20 2020)

:tada: This release contains work from a new contributor! :tada:

Thank you, Jeroen Zwartepoorte (@jpzwarte), for all your work!

🚀 Enhancement

📝 Documentation

Authors: 2


v0.4.1 (Wed Apr 15 2020)

🐛 Bug Fix

Authors: 1


v0.4.0 (Fri Mar 27 2020)

🚀 Enhancement

  • Add toggle button to to docs page and save custom themes on initilization #97 (@tskarhed)

Authors: 1


v0.3.1 (Fri Mar 13 2020)

🐛 Bug Fix

Authors: 1


v0.3.0 (Tue Feb 04 2020)

🚀 Enhancement

  • Create a React hook for getting dark-mode state #89 (@adierkens)

🐛 Bug Fix

🔩 Dependency Updates

Authors: 4


v0.2.0 (Tue Dec 10 2019)

🚀 Enhancement

  • feat: add media query matcher for operating system theme control #73 (@Swiftwork)

Authors: 1


v0.1.9 (Wed Oct 30 2019)

🐛 Bug Fix

🔩 Dependency Updates

Authors: 3


v0.1.8 (Mon Oct 28 2019)

🐛 Bug Fix

  • Listen for docsRendered event so it also picks up the correct theme. #61 (@adamyonk)

🏠 Internal

🔩 Dependency Updates

Authors: 3


v0.1.6 (Tue Sep 03 2019)

🐛 Bug Fix

Authors: 1


v0.1.5 (Tue Aug 27 2019)

🐛 Bug Fix

Authors: 1


v0.1.4 (Wed Jul 17 2019)

🐛 Bug Fix

  • Subscribed to another event in order to trigger theme change on story change #10 (@carlesnunez)

Authors: 1


v0.1.3 (Wed Mar 13 2019)

🐛 Bug Fix

Authors: 1


v0.1.2 (Wed Mar 13 2019)

🐛 Bug Fix

Authors: 1


v0.1.1 (Wed Mar 13 2019)

🐛 Bug Fix

Authors: 2


v0.1.0 (Fri Mar 08 2019)

🚀 Enhancement

Authors: 1


v0.0.4 (Wed Mar 06 2019)

⚠️ Pushed to master

Authors: 1


v0.0.3 (Wed Mar 06 2019)

⚠️ Pushed to master

Authors: 1


v0.0.2 (Wed Mar 06 2019)

⚠️ Pushed to master

Authors: 1