Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/hipstersmoothie/storybook-dark-mode

A storybook addon that lets your users toggle between dark and light mode.
https://github.com/hipstersmoothie/storybook-dark-mode

add-on dark-theme storybook

Last synced: about 5 hours ago
JSON representation

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

Awesome Lists containing this project

README

        

# storybook-dark-mode

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

![Example](./example.gif)

## Installation

Install the following npm module:

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

or with yarn:

```sh
yarn add -D storybook-dark-mode
```

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

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

## Upgrade from earlier version

Change in `.storybook/main.js`

```diff
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:

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

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

```js
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.

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

You can also pass an array to apply multiple classes.

```js
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 `` 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 `` is styled according to a parent's class, in that case it can be set to `html`.

```js
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.

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

### React

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

```js
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 (

{props.children}

);
}

export const decorators = [renderStory => {renderStory()})];
```

#### Theme Knobs

If you want to have you UI's dark mode separate from you components' dark mode, implement this global decorator:

```js
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.

```js
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 (

{props.children}

);
}

export const decorators = [renderStory => {renderStory()})];
```

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

```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 (





);
}
}
};
```

## Contributors ✨

Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/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](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!