# storybook-addon-themes

> A storybook addon to switch between different themes for your preview

Latest version **6.1.0** (published 2021-04-05) · MIT license · 0 weekly downloads

## Install

```sh
npm install storybook-addon-themes
pnpm add storybook-addon-themes
yarn add storybook-addon-themes
bun add storybook-addon-themes
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 6.1.0 |
| Published | 2021-04-05 |
| First published | 2018-01-22 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 8 |
| Unpacked size | 216.5 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 85 |
| Author | tonai |
| Maintainers | tonai |
| Keywords | addon, frontend, react, reactjs, storybook, storybookjs, svelte, theme, tool, ui, user interface, vue, vuejs, storybook-addon, style |

## Links

- npm: https://www.npmjs.com/package/storybook-addon-themes
- Repository: https://github.com/tonai/storybook-addon-themes
- Issues: https://github.com/tonai/storybook-addon-themes/issues
- npm.io page: https://npm.io/package/storybook-addon-themes

## Dependencies (8)

- [global](https://npm.io/package/global.md) ^4.4.0
- [core-js](https://npm.io/package/core-js.md) ^3.6.4
- [memoizerific](https://npm.io/package/memoizerific.md) ^1.11.3
- [@storybook/api](https://npm.io/package/@storybook/api.md) ^6.0.0
- [@storybook/addons](https://npm.io/package/@storybook/addons.md) ^6.0.0
- [@storybook/theming](https://npm.io/package/@storybook/theming.md) ^6.0.0
- [@storybook/components](https://npm.io/package/@storybook/components.md) ^6.0.0
- [@storybook/core-events](https://npm.io/package/@storybook/core-events.md) ^6.0.0

## Alternatives

- [mobx-react](https://npm.io/package/mobx-react.md) — 2.8M weekly downloads
- [rc-tree](https://npm.io/package/rc-tree.md) — 2.6M weekly downloads
- [@react-oauth/google](https://npm.io/package/@react-oauth/google.md) — 1.3M weekly downloads
- [@wagmi/connectors](https://npm.io/package/@wagmi/connectors.md) — 877.0K weekly downloads
- [vee-validate](https://npm.io/package/vee-validate.md) — 836.4K weekly downloads

## Recent versions

- 6.1.0 (latest) — 2021-04-05
- 6.0.0-alpha.2 (next) — 2020-03-23
- 6.0.1 — 2020-12-08
- 6.0.0 — 2020-08-25
- 5.5.0 — 2020-08-24
- 5.4.1 — 2020-03-23
- 5.4.0 — 2020-03-05
- 6.0.0-alpha.1 — 2020-02-13
- 5.3.0 — 2020-01-30
- 5.2.0 — 2019-07-09
- 5.1.0 — 2019-06-04
- 5.0.0 — 2019-03-15
- 4.0.0 — 2019-03-15
- 3.0.0 — 2019-03-15
- 0.0.4 — 2018-01-22
- … 2 more at https://npm.io/package/storybook-addon-themes/versions

## README

# Storybook Addon Themes

Greatly inspired by [@storybook/addon-backgrounds](https://github.com/storybooks/storybook/tree/next/addons/backgrounds).

This Storybook Theme Decorator can be used to add a custom HTML class or classes to the preview in [Storybook](https://storybook.js.org).

![Demo](media/demo.gif)

## Compatibility

This version is compatible with storybook version `6.0.x`.

## Installation

```sh
npm i -D storybook-addon-themes
```

## Getting started

Then activate the addon by adding it to the storybook `main.js` file (located in the Storybook config directory):

```jsx
module.exports = {
  addons: [
    // Maybe other addons here...
    'storybook-addon-themes'
    // Or here...
  ],
};
```

See the [storybook documentation](https://storybook.js.org/docs/addons/using-addons/) for more informations.

## Parameters

The `themes` parameter accept an array of `Theme` object.

Each `Theme` is an object with the following properties:

* `name` (`string`): Name of the theme
* `class` (`string | string[]` - optional): HTML class(es) associated with the theme
* `color` (`string`): The color of the badge in the theme selector
* `default` [_deprecated_] (`boolean` - optional): Is the theme selected by default?

The `themes` parameter also accept an object with the following properties:

* `default` (`string` - optional): Name of theme selected by default
* `list` (`Theme[]` - required): The list of themes
* `clearable` (`boolean` - optional - default is `true`): Can the user clear the selected theme ?
* `disable` (`boolean` - optional): Disable the addon for a story
* `Decorator` (`Component` - optional): A component to use as the decorator component ([see below](#custom-decorator) for more information)
* `onChange` (`(themeName: Theme) => void` - optional): A callback that will be executed when the theme changes
* `target` (`string` - optional): Target element selected with `document.querySelector()` to which classes are applied. Defaults to `body`, `root` if classes should be applied to `documentElement`.

## Configuration

### Globally

You can configure the themes globally in the storybook `preview.js` file:

```jsx
export const parameters = {
  themes: {
    default: 'twitter',
    list: [
      { name: 'twitter', class: 'theme-twt', color: '#00aced' },
      { name: 'facebook', class: 'theme-fb', color: '#3b5998' }
    ],
  },
};
```

For backward compatibility `default` (`boolean`) can also be set directly on `Theme` object.
**This has been deprecated** because of the difficulty of changing the default theme due to the need to redefine all `Theme` objects.

```jsx
// deprecated
export const parameters = {
  themes: [
      { name: 'twitter', class: 'theme-twt', color: '#00aced', default: true },
      { name: 'facebook', class: 'theme-fb', color: '#3b5998' }
  ],
};
```

See the [storybook documentation](https://storybook.js.org/docs/addons/using-addons/#global-configuration) for more informations.

### In story (Component Story Format)

Or configure the themes in your story file like this:

```jsx
export default {
  title: 'CSF|Button',
  component: Button,
  parameters: {
    themes: {
      default: 'twitter',
      list: [
        { name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
        { name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
      ],
    },
  },
};
```

If you only want to activate the addon or override the themes for a specific story you can write:

```jsx
export default {
  title: 'CSF|Button',
  component: Button,
};

export const withText = () => <Button onClick={action('clicked')}>Hello Button</Button>;
withText.story = {
  parameters: {
    themes: {
      default: 'twitter',
      list: [
        { name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
        { name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
      ],
    },
  },
};
```

### In story (StoriesOf API)

Alternatively with the old StoriesOf API:

```jsx
import { storiesOf } from '@storybook/react'; // <- or your storybook framework

storiesOf('StoriesOf|Button', module)
  .addParameters({
    themes: {
      default: 'twitter',
      list: [
        { name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
        { name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
      ],
    },
  })
  .add('with text', () => <button>Click me</button>);
```

And for a single story:

```jsx
import { storiesOf } from '@storybook/react';

storiesOf('StoriesOf|Button', module)
  .add('with text', () => <button>Click me</button>, {
    themes: {
      list: [
        { name: 'red', class: 'theme-red', color: 'rgba(255, 0, 0)' },
      ],
    },
  });

```

### Overwriting single properties

You can also only override a single key on the themes parameter, for instance to set a different default value for a single story:
```jsx
export default {
  title: 'CSF|Button',
  component: Button,
};

export const withText = () => <Button onClick={action('clicked')}>Hello Button</Button>;
withText.story = {
  parameters: {
    themes: {
      default: 'facebook',
    },
  },
};
```

## Usage with decorator

By default the classes will be added to the `body` element or the element configured with `target`.

But in this case your theme will not be visible by other addons (like [@storybook/addon-storyshots](https://github.com/storybookjs/storybook/tree/next/addons/storyshots)).

To fix this you can add the `withThemes` decorator in your stories.

But the decorator method is not available for all frameworks

See [here](#framework-support-table) for the list of supported framework.

### Globally

Setup the decorator globally in the `preview.js` file:

```jsx
import { addDecorator } from '@storybook/react'; // <- or your storybook framework
import { withThemes } from 'storybook-addon-themes/react'; // <- or your storybook framework

addDecorator(withThemes);

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  themes: {
    default: 'twitter',
    list: [
      { name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
      { name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
    ],
  },
};
```

### In story (Component Story Format)

Or in your story file (for all stories in that file):

```jsx
export default {
  title: 'CSF|Button',
  component: Button,
  decorators: [ withThemes ],
  parameters: {
    themes: {
      default: 'twitter',
      list: [
        { name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
        { name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
      ],
    },
  },
};
```

Or just for a specific story:

```jsx
export const withText = () => <Button onClick={action('clicked')}>Hello Button</Button>;
withText.story = {
  decorators: [ withThemes ],
  parameters: {
    themes: {
      default: 'twitter',
      list: [
        { name: 'twitter', class: ['theme-twt', 'light-mode'], color: '#00aced' },
        { name: 'facebook', class: ['theme-fb', 'dark-mode'], color: '#3b5998' },
      ],
    },
  },
};
```

### In story (StoriesOf API)

And alternatively with the old StoriesOf API:

```jsx
import { storiesOf } from '@storybook/react'; // <- or your storybook framework
import { withThemes } from 'storybook-addon-themes/react';

storiesOf('StoriesOf|Button', module)
  .addDecorator(withThemes)
  .add('with text', () => <button>Click me</button>);
```

### Custom decorator

#### General

You can provide a component that will be used as decorator using the `Decorator` option in the `theme` parameter.

The decorator will get the following properties :

* `theme`: The selected theme or `undefined` if none is selected.
* `themes`: The list of themes as provided in the `list` option of the `theme` parameter.
* `themeClasses`: The formatted theme classes of the selected theme (if the `class` option exists on the selected theme).
* `themeName`: The name of the selected theme (equal to `none` if none is selected).

Don't forget to render the story using the `children` prop (React/HTML) or the `<slot></slot>` element (Vue/Svelte).

#### HTML example

To manage reactivity with the HTML storybook your decorator must return an array containing two elements :

* the HTML element to display in the story
* An update callback that will be called when the theme change. Like the decorator, the callback will receive the same props (without `children`).

Example of a customized decorator that use a CSS file for changing the theme:

```js
function getOrCreate(id) {
  const elementOnDom = document.getElementById(id);
  if (elementOnDom) {
    return elementOnDom;
  }

  const element = document.createElement('link');
  element.setAttribute('id', id);
  element.setAttribute('rel', 'stylesheet');
  return element;
}

function Decorator(props) {
  const { children } = props;

  function setStyles({ theme, themeName }) {
    const link = getOrCreate('theme-stylesheet');
    if (!theme) {
      link.parentNode && link.parentNode.removeChild(link);
    } else {
      link.href = themeName === 'facebook' ? 'Button-fb.css' : 'Button-twt.css';
      children.appendChild(link);
    }
  }
  setStyles(props);

  return [children, setStyles];
}
```

#### React example

Same example as above for React:

```js
function Decorator(props) {
  const { children, themeName } = props;
  return (
    <>
      {children}
      {themeName === 'twitter' && <link rel="stylesheet" href="twitter.css"/>}
      {themeName === 'facebook' && <link rel="stylesheet" href="facebook.css"/>}
    </>
  );
};
```

## Framework Support Table

| | [React](app/react)|[React Native](app/react-native)|[Vue](app/vue)|[Angular](app/angular)| [Polymer](app/polymer)| [Mithril](app/mithril)| [HTML](app/html)| [Marko](app/marko)| [Svelte](app/svelte)| [Riot](app/riot)| [Ember](app/ember)| [Preact](app/preact)|
| ----------- |:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|:-------:|
|Usage without decorator |+| |+|+|+|+|+|+|+|+|+|+|
|Usage with decorator    |+| |+| | | |+| |+| | | |

---
_Source: https://npm.io/package/storybook-addon-themes · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
