DEV Community

Cover image for How to customize storybook (custom theme and layout option)?
Vishesh Tiwari
Vishesh Tiwari

Posted on

How to customize storybook (custom theme and layout option)?

Hi devs,

In this article , I am going to discuss about how can we customize our storybook which includes -

  • Custom theme ( dark or light )
  • Custom layout ## How to setup custom background colour with theme ? I am assuming you have done basic setup of storybook. If you have then in your project structure file named preview.tsx or preview.ts will be present where we will all customization code , if this file not present then you can create it. And second file you need create name as CustomTheme.ts which having content as below

import { create } from '@storybook/theming';
import logo from './my-app-logo.svg';
export default create({
  base: 'light',
  brandTitle: 'My app name',
  brandUrl: 'https://myapp.com',
  brandImage: logo,
  appContentBg: 'white',
  appBorderColor: 'grey',
  appBorderRadius: 4,
});

Enter fullscreen mode Exit fullscreen mode

After that create one file named as manager.ts if it is not present on your .storybook work directory and this

import { addons } from '@storybook/addons';

import CustomTheme from './CustomTheme';

addons.setConfig({
  theme: CustomTheme,
});

Enter fullscreen mode Exit fullscreen mode

Now lets move to preview.tsx file , we will start defining some configuration as below with withThemeProvider variable.


const Theme = {
  LIGHT: 'light',
  DARK: 'dark',
};

const customBackgrounds = {
  values: [
    {
      name: Theme.LIGHT,
      value: 'white',
    },
    {
      name: Theme.DARK,
      value: '#333333',
    },
  ],
};

const parameters = {
  backgrounds: customBackgrounds,
  viewport: {
  },
};


const getThemeColor = (theme: string) => {
  const { value } = parameters.backgrounds.values.find(({ name }) => name === theme);
  return value;
};

const withThemeProvider = (Story, storyContext) => {
  const { globals } = storyContext;
  const currentLayout: string = globals.layout;
  const currentFont: BackyardFonts = globals.font;
  const currentBackGround = globals.backgrounds?.value ?? 'white';
  const currentTheme: any = currentBackGround === 'white' ? Theme.LIGHT : Theme.DARK;
  const currentBackground: string = getThemeColor(currentTheme);

  useEffect(() => {
    document.body.setAttribute('backgroundColor', currentBackground);
  }, [currentBackground, currentFont]);

  return (
    <ThemeProvider
      theme={currentTheme}
      font={currentFont}
    >
      <GlobalStyles />
      <Story />
    </ThemeProvider>
  );
};

const decorators = [withThemeProvider];
Enter fullscreen mode Exit fullscreen mode

After adding these configuration you can change background colour with storybook theme.

How to setup custom layout ?

For setting up storybook with custom layout you need to following setup given below -

  • Defining custom layout which is going to appear as option in storybook

const Layout = {
  DEFAULT: 'default',
  WITH_L1: 'Layout 1',
  WITH_L2: 'Layout 2',
};
Enter fullscreen mode Exit fullscreen mode
  • Now we need add layout as option using global parameter

const globalTypes = {
  layout: {
    description: 'Layouts',
    defaultValue: Layout.DEFAULT,
    toolbar: {
      title: 'Layout',
      items: [
        { value: Layout.DEFAULT, title: 'Default' },
        { value: Layout.WITH_L1, title: 'Layout 1' },
        { value: Layout.WITH_L2, title: 'Layout 2' },
      ],
      dynamicTitle: true,
    },
  },
};

Enter fullscreen mode Exit fullscreen mode

Now we to do some slight changes in withThemeProvider

const withThemeProvider = (Story, storyContext) => {
  const { globals } = storyContext;
  const currentLayout: string = globals.layout;
  const currentBackground: string = getThemeColor(currentTheme);

  return (
    <>
      {currentLayout === Layout.DEFAULT && <Story />}
      {currentLayout === Layout.WITH_L1 && (
        <L1>
          <Story />
        </L1>
      )}
      {currentLayout === Layout.WITH_SIDEBAR && (
        <L2>
          <Story />
        </L2>
      )}
    </>
  );
};

Enter fullscreen mode Exit fullscreen mode

You can define layouts as component anywhere and export it in preview.tsx file -

const L1 = ({ children }) => (
  <StyledRootWrapper>
    <StyledNavContainer />
    <StyledChildren>{children}</StyledChildren>
  </StyledRootWrapper>
);

const L2 = ({ children }) => (
  <StyledRootWrapper>
    <StyledNavContainer />
    <StyledChildren>{children}</StyledChildren>
  </StyledRootWrapper>
);
Enter fullscreen mode Exit fullscreen mode

Whole code snippet look like for preview.tsx -

import { ThemeProvider } from '@backyard/react';
import { GlobalStyles } from './Container';
import { L1, L2 } from './customLayout';
import { useEffect } from 'react';
import {
  customBackgrounds,
  Layout,
  Theme,
} from './configurations';
import React from 'react';

const parameters = {
  backgrounds: customBackgrounds,
};

const getThemeColor = (theme: string) => {
  const { value } = parameters.backgrounds.values.find(({ name }) => name === theme);
  return value;
};

const withThemeProvider = (Story, storyContext) => {
  const { globals } = storyContext;
  const currentLayout: string = globals.layout;
  const currentBackGround = globals.backgrounds?.value ?? 'white';
  const currentTheme: any = currentBackGround === 'white' ? Theme.LIGHT : Theme.DARK;
  const currentBackground: string = getThemeColor(currentTheme);

  useEffect(() => {
    document.body.setAttribute('backgroundColor', currentBackground);
  }, [currentBackground, currentFont]);

  return (
      <ThemeProvider
      theme={currentTheme}>
      {currentLayout === Layout.DEFAULT && <Story />}
      {currentLayout === Layout.WITH_L1 && (
        <L1>
          <Story />
        </L1>
      )}
      {currentLayout === Layout.WITH_SIDEBAR && (
        <L2>
          <Story />
        </L2>
      )}
    </ThemeProvider>
  );
};

const globalTypes = {
  layout: {
    description: 'Layouts',
    defaultValue: Layout.DEFAULT,
    toolbar: {
      title: 'Layout',
      items: [
        { value: Layout.DEFAULT, title: 'Default' },
        { value: Layout.WITH_L1, title: 'Layout 1' },
        { value: Layout.WITH_L2, title: 'Layout 2' },
      ],
      dynamicTitle: true,
    },
  },
};


const decorators = [ withThemeProvider];

export { decorators, globalTypes, parameters };
Enter fullscreen mode Exit fullscreen mode

After that completing these steps you can find option dropdown at top of storybook toolbar.

Buy Me A Coffee

Top comments (1)

Collapse
 
cherry_wills_27d3a93aff39 profile image
Cherry wills

"Great explanation! Customizing Storybook with themes and layouts seems super flexible. Thanks for sharing the detailed setup steps!"

Dan and Shay Wife Died