The Toolbars addon controls global story rendering options from Storybook's toolbar UI. It's a general purpose addon that can be used to:
- set a theme for your components
- set your components' internationalization (i18n) locale
- configure just about anything in Storybook that makes use of a global variable
Toolbars is implemented using Storybook Args (SB6.0+): dynamic variables that trigger a story re-render when they are set.
- [Get started](#get-started)
- [Installation](#installation)
- [Configure menu UI](#configure-menu-ui)
- [Create a decorator](#create-a-decorator)
- [Advanced usage](#advanced-usage)
- [Advanced menu configuration](#advanced-menu-configuration)
- [Consuming global args from within a story](#consuming-global-args-from-within-a-story)
- [Consuming global args from within an addon](#consuming-global-args-from-within-an-addon)
- [FAQs](#faqs)
- [How does this compare to `addon-contexts`?](#how-does-this-compare-to-addon-contexts)
## Get started
To get started with `addon-toolbars`:
1. [install the addon](#installation),
2. [configure the menu UI](#configure-menu-ui)
3. [Create a decorator to implement custom logic](#create-a-decorator).
### Installation
First, install the package:
```sh
npm install @storybook/addon-toolbars -D # or yarn
```
Then add it to your `.storybook/main.js` config:
```js
module.exports = {
addons: ['@storybook/addon-toolbars'],
};
```
### Configure menu UI
Addon-toolbars has a simple, declarative syntax for configuring toolbar menus. You can add toolbars by adding `globalArgTypes` with a `toolbar` annotation, in `.storybook/preview.js`:
```js
export const globalArgTypes = {
theme: {
name: 'Theme'
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
icon: 'circlehollow',
// array of plain string values or MenuItem shape (see below)
items: ['light', 'dark'],
},
},
};
```
You should see a dropdown in your toolbar with options `light` and `dark`.
### Create a decorator
Now, let's wire it up! We can consume our new `theme` global arg in a decorator using the `context.globalArgs.theme` value.
For example, suppose you are using `styled-components`. You can add a theme provider decorator to your `.storybook/preview.js` config:
```ts
import { ThemeProvider } from 'styled-components';
import { StoryContext, StoryGetter, StoryWrapper } from '@storybook/addons';
const withThemeProvider: StoryWrapper = (Story: StoryGetter, context: StoryContext) => {
// context.globalArgs.theme here will be either 'light' or 'dark'
// getTheme being a function retrieving the actual theme object from that value
const theme = getTheme(context.globalArgs.theme);
return (
);
};
export const decorators = [withThemeProvider];
```
## Advanced usage
The previous section shows the common case. There are two advanced use cases: (1) [advanced menu configurations](#advanced-menu-configuration), (2) [consuming global args inside a story](#consuming-global-args-from-within-a-story).
### Advanced menu configuration
The default menu configuration is simple: everything's a string! However, the Toolbars addon also support configuration options to tweak the appearance of the menu:
```ts
type MenuItem {
/**
* The string value of the menu that gets set in the global args
*/
value: string,
/**
* The main text of the title
*/
title: string,
/**
* A string that gets shown in left side of the menu, if set
*/
left?: string,
/**
* A string that gets shown in right side of the menu, if set
*/
right?: string,
/**
* An icon that gets shown in the toolbar if this item is selected
*/
icon?: icon,
}
```
Thus if you want to show right-justified flags for an internationalization locale, you might set up the following configuration in `.storybook/preview.js`:
```js
export const globalArgTypes = {
locale: {
name: 'Locale',
description: 'Internationalization locale',
defaultValue: 'en',
toolbar: {
icon: 'globe',
items: [
{ value: 'en', right: '🇺🇸', title: 'English' },
{ value: 'fr', right: '🇫🇷', title: 'Français' },
{ value: 'es', right: '🇪🇸', title: 'Español' },
{ value: 'zh', right: '🇨🇳', title: 'ä¸æ–‡' },
{ value: 'kr', right: '🇰🇷', title: 'í•œêµì–´' },
],
},
},
};
```
### Consuming global args from within a story
The recommended usage, as shown in the examples above, is to consume global args from within a decorator and implement a global setting that applies to all stories. But sometimes it's useful to use toolbar options inside individual stories.
Storybook's `globalArgs` are available via the story context:
```js
const getCaptionForLocale = (locale) => {
switch(locale) {
case 'es': return 'Hola!';
case 'fr': return 'Bonjour!';
case 'kr': return '안녕하세요!';
case 'zh': return 'ä½ å¥½!';
default:
return 'Hello!',
}
}
export const StoryWithLocale = ({ globalArgs: { locale } }) => {
const caption = getCaptionForLocale(locale);
return <>{caption}>
};
```
**NOTE:** In Storybook 6.0, if you set the global option `passArgsFirst`, the story context is passes as the second argument:
```js
export const StoryWithLocale = (args, { globalArgs: { locale } }) => {
const caption = getCaptionForLocale(locale);
return <>{caption}>;
};
```
### Consuming global args from within an addon
There is a hook available in `@storybook/api` to retrieve the global args: `useGlobalArgs()`
Following the previous example of the ThemeProvider, if you want for instance to display the current theme inside a Panel:
```js
import { useGlobalArgs } from '@storybook/api';
import { AddonPanel, Placeholder, Separator, Source, Spaced, Title } from '@storybook/components';
const ThemePanel = props => {
const [{ theme: themeName }] = useGlobalArgs();
const theme = getTheme(themeName);
return (
{theme ? (
{theme.name}
The full theme object/p>
) : (
No theme selected
)}
);
};
```
## FAQs
### How does this compare to `addon-contexts`?
`Addon-toolbars` is the successor to `addon-contexts`, which provided convenient global toolbars in Storybook's toolbar.
The primary difference between the two packages is that `addon-toolbars` makes use of Storybook's new **Story Args** feature, which has the following advantages:
- **Standardization**. Args are built into Storybook in 6.x. Since `addon-toolbars` is based on args, you don't need to learn any addon-specific APIs to use it.
- **Ergonomics**. Global args are easy to consume [in stories](#consuming-global-args-from-within-a-story), in [Storybook Docs](https://github.com/storybookjs/storybook/tree/master/addons/docs), or even in other addons.
* **Framework compatibility**. Args are completely framework-independent, so `addon-toolbars` is compatible with React, Vue, Angular, etc. out of the box with no framework logic needed in the addon.