Join live session: Top 8 Storybook myths holding your team back
Docs
Storybook Docs

Toolbars & globals

Watch a video tutorial

Storybook ships with toolbar addons to control the viewport and background the story renders in. You can also create toolbar items which control special “globals”. You can then read the global values to create decorators to control story rendering.

Toolbars and globals

Globals

Globals in Storybook represent “global” (as in not story-specific) inputs to the rendering of the story. As they aren’t specific to the story, they aren’t passed in the args argument to the story function (although they are accessible as context.globals). Instead, they are typically used in decorators, which apply to all stories.

When the globals change, the story re-renders and the decorators rerun with the new values. The easiest way to change globals is to create a toolbar item for them.

Global types and the toolbar annotation

Storybook has a simple, declarative syntax for configuring toolbar menus. In your .storybook/preview.js|ts, you can add your own toolbars by creating globalTypes with a toolbar annotation:

.storybook/preview.ts
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  globalTypes: {
    theme: {
      description: 'Global theme for components',
      toolbar: {
        // The label to show for this toolbar item
        title: 'Theme',
        icon: 'circlehollow',
        // Array of plain string values or MenuItem shape (see below)
        items: ['light', 'dark'],
        // Change title based on selected value
        dynamicTitle: true,
      },
    },
  },
  initialGlobals: {
    theme: 'light',
  },
};
 
export default preview;

As globals are global you can only set globalTypes and initialGlobals in .storybook/preview.js|ts.

When you start your Storybook, your toolbar should have a new dropdown menu with the light and dark options.

Create a decorator

We have a global implemented. Let's wire it up! We can consume our new theme global in a decorator using the context.globals.theme value.

For example, suppose you are using styled-components. You can add a theme provider decorator to your .storybook/preview.js|ts config:

.storybook/preview.ts
// Replace your-framework with the framework you are using (e.g., solid, qwik)
import { Preview } from '@storybook/your-framework';
 
import { MyThemes } from '../my-theme-folder/my-theme-file';
 
const preview: Preview = {
  decorators: [
    (story, context) => {
      const selectedTheme = context.globals.theme || 'light';
      const theme = MyThemes[selectedTheme];
      return (
        // Your theme provider and other context providers go here
      )
    },
  ],
};
 
export default preview;

Setting globals on a story

The ability to set globals on a story or component is available in Storybook 8.3+. Some addons, like backgrounds and viewport, have been updated to use the globals API when a feature flag is enabled.

When a global value is changed with a toolbar menu in Storybook, that value continues to be used as you navigate between stories. But sometimes a story requires a specific value to render correctly, e.g., when testing against a particular environment.

To ensure that a story always uses a specific global value, regardless of what has been chosen in the toolbar, you can set the globals annotation on a story or component. This overrides the global value for those stories and disables the toolbar menu for that global when viewing the stories.

Button.stories.ts|tsx
// Replace your-framework with the name of your framework
import type { Meta, StoryObj } from '@storybook/your-framework';
 
import { Button } from './Button';
 
const meta: Meta<typeof Button> = {
  component: Button,
  globals: {
    // 👇 Set background value for all component stories
    backgrounds: { value: 'gray', grid: false },
  },
};
 
export default meta;
type Story = StoryObj<typeof Button>;
 
export const OnDark: Story = {
  globals: {
    // 👇 Override background value for this story
    backgrounds: { value: 'dark' },
  },
};

In the example above, Storybook will force all Button stories to use a gray background color, except the OnDark story, which will use the dark background. For all Button stories, the toolbar menu will be disabled for the backgrounds global, with a tooltip explaining that the global is set at the story level.

Configuring a story's globals annotation to override the project-level global settings is useful but should be used with moderation. Globals that are not defined at the story level can be selected interactively in Storybook's UI, allowing users to explore every existing combination of values (e.g., global values, args). Setting them at the story level will disable that control, preventing users from exploring the available options.

Advanced usage

So far, we've created and used a global inside Storybook.

Now, let's take a look at a more complex example. Suppose we wanted to implement a new global called locale for internationalization, which shows a flag on the right side of the toolbar.

In your .storybook/preview.js|ts, add the following:

.storybook/preview.ts
// Replace your-framework with the framework you are using (e.g., react, vue3)
import { Preview } from '@storybook/your-framework';
 
const preview: Preview = {
  globalTypes: {
    locale: {
      description: 'Internationalization locale',
      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: '한국어' },
        ],
      },
    },
  },
  initialGlobals: {
    locale: 'en',
  },
};
 
export default preview;

The icon element used in the examples loads the icons from the @storybook/components package. See here for the list of available icons that you can use.

To use toolbars, you must install the @storybook/addon-toolbars add-on, which is included by default in @storybook/addon-essentials.

Adding the configuration element right will display the text on the right side in the toolbar menu once you connect it to a decorator.

Here's a list of the available configuration options.

MenuItemTypeDescriptionRequired
valueStringThe string value of the menu that gets set in the globalsYes
titleStringThe main text of the titleYes
rightStringA string that gets displayed on the right side of the menuNo
iconStringAn icon that gets shown in the toolbar if this item is selectedNo

Consuming globals from within a story

We recommend consuming globals from within a decorator and defining a global setting for all stories.

But we're aware that sometimes it's more beneficial to use toolbar options on a per-story basis.

Using the example above, you can modify any story to retrieve the Locale global from the story context:

MyComponent.stories.ts|tsx
import type { Meta, StoryObj } from '@storybook/react';
 
import { MyComponent } from './MyComponent';
 
const meta: Meta<typeof MyComponent> = {
  component: MyComponent,
};
 
export default meta;
type Story = StoryObj<typeof MyComponent>;
 
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 = {
  render: (args, { globals: { locale } }) => {
    const caption = getCaptionForLocale(locale);
    return <p>{caption}</p>;
  },
};

Consuming globals from within an addon

If you're working on a Storybook addon and need to retrieve globals, you can do so. The @storybook/manager-api package provides a hook for this scenario. You can use the useGlobals() hook to retrieve any globals you want.

Using the ThemeProvider example above, you could expand it to display which theme is active inside a panel as such:

your-addon-register-file.js
import React from 'react';
 
import { useGlobals } from '@storybook/manager-api';
 
import { AddonPanel, Placeholder, Separator, Source, Spaced, Title } from '@storybook/components';
 
import { MyThemes } from '../my-theme-folder/my-theme-file';
 
// Function to obtain the intended theme
const getTheme = (themeName) => {
  return MyThemes[themeName];
};
 
const ThemePanel = (props) => {
  const [{ theme: themeName }] = useGlobals();
 
  const selectedTheme = getTheme(themeName);
 
  return (
    <AddonPanel {...props}>
      {selectedTheme ? (
        <Spaced row={3} outer={1}>
          <Title>{selectedTheme.name}</Title>
          <p>The full theme object</p>
          <Source
            code={JSON.stringify(selectedTheme, null, 2)}
            language="js"
            copyable
            padded
            showLineNumbers
          />
        </Spaced>
      ) : (
        <Placeholder>No theme selected</Placeholder>
      )}
    </AddonPanel>
  );
};

Updating globals from within an addon

If you're working on a Storybook addon that needs to update the global and refresh the UI, you can do so. As mentioned previously, the @storybook/manager-api package provides the necessary hook for this scenario. You can use the updateGlobals function to update any global values you need.

For example, if you were working on a toolbar addon, and you want to refresh the UI and update the global once the user clicks on a button:

your-addon-register-file.js
import React, { useCallback } from 'react';
 
import { FORCE_RE_RENDER } from '@storybook/core-events';
import { useGlobals } from '@storybook/manager-api';
 
import { IconButton } from '@storybook/components';
import { OutlineIcon } from '@storybook/icons';
 
import { addons } from '@storybook/preview-api';
 
const ExampleToolbar = () => {
  const [globals, updateGlobals] = useGlobals();
 
  const isActive = globals['my-param-key'] || false;
 
  // Function that will update the global value and trigger a UI refresh.
  const refreshAndUpdateGlobal = () => {
    // Updates Storybook global value
    updateGlobals({
      ['my-param-key']: !isActive,
    }),
      // Invokes Storybook's addon API method (with the FORCE_RE_RENDER) event to trigger a UI refresh
      addons.getChannel().emit(FORCE_RE_RENDER);
  };
 
  const toggleOutline = useCallback(() => refreshAndUpdateGlobal(), [isActive]);
 
  return (
    <IconButton
      key="Example"
      active={isActive}
      title="Show a Storybook toolbar"
      onClick={toggleOutline}
    >
      <OutlineIcon />
    </IconButton>
  );
};