How to theme Material UI inside Storybook

10,976

Solution 1

First, I suggest you to move your theme into a separate file (such as src/stylesheet so you can access it from different files (your global App component and your storybook preview file).

// src/stylesheet.ts

import { createMuiTheme } from '@material-ui/core/styles';

export const muiTheme = createMuiTheme({
  palette: {
    primary: {
      main: "#ff0000"
    }
  },
  typography: {
    fontFamily: 'Nunito Sans, sans-serif',
    button: {
      textTransform: 'none'
    }
  },
  shape: {
    borderRadius: 3
  }
})

Then, you need to setup your storybook the same way you set up your react app. To do so, try to create a file called: .storybook/preview.js and put this inside of it:

// .storybook/preview.js

import React from 'react';

import { addDecorator } from '@storybook/react';
import { ThemeProvider } from '@material-ui/core/styles';

import { muiTheme } from '../src/stylesheet';

addDecorator((story) => (
    <ThemeProvider theme={muiTheme}>{story()}</ThemeProvider>
));

It will wrap all your stories inside of the ThemeProvider.

In your app, you can can also have a global App component which will encapsulate the whole app within the ThemeProvider

More help: https://storybook.js.org/docs/basics/writing-stories/

Solution 2

This is the only solution that worked for me with MUI v5:

// .storybook/main.js

const path = require('path');
const toPath = (filePath) => path.join(process.cwd(), filePath);

module.exports = {
   webpackFinal: async (config) => {
    return {
       ...config,
      resolve: {
         ...config.resolve,
        alias: {
          ...config.resolve.alias,
          '@emotion/core': toPath('node_modules/@emotion/react'),
          'emotion-theming': toPath('node_modules/@emotion/react'),
        },
      },
    };
  },
};


// .storybook/preview.js

import { ThemeProvider, createTheme } from '@mui/material/styles';
import { ThemeProvider as Emotion10ThemeProvider } from 'emotion-theming';

const defaultTheme = createTheme(); // or your custom theme

const withThemeProvider = (Story, context) => {
  return (
    <Emotion10ThemeProvider theme={defaultTheme}>
      <ThemeProvider theme={defaultTheme}>
        <Story {...context} />
      </ThemeProvider>
    </Emotion10ThemeProvider>
  );
};

export const decorators = [withThemeProvider];

// ...other storybook exports

It's from the MUI migration guide but it took me unnecessarily long to find so I want to share it here: https://mui.com/guides/migration-v4/

Solution 3

For Storybook 6.3+ it should look like the following

Update preview.js with:

import React from 'react';
import { theme } from './src/theme'; // whereever you have defined your material ui theme

export const decorators = [
  Story => (
    <ThemeProvider theme={theme}>
      <Story />
    </ThemeProvider>
  ),
];

More details on how to decorate your stories here: https://storybook.js.org/docs/react/writing-stories/decorators

And creating your theme for Material UI here: https://material-ui.com/customization/theming/

Share:
10,976
Asif Kabani
Author by

Asif Kabani

Updated on July 21, 2022

Comments

  • Asif Kabani
    Asif Kabani almost 2 years

    Currently this is what I am doing, passing a ThemeProvider above my component file:

    import React from 'react';
    import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
    import MUIButton from '@material-ui/core/Button';
    
    const theme = createMuiTheme({
      palette: {
        primary: {
          main: "#ff0000"
        }
      },
      typography: {
        fontFamily: 'Nunito Sans, sans-serif',
        button: {
          textTransform: 'none'
        }
      },
      shape: {
        borderRadius: 3
      }
    })
    
    
    export default ({ variant, children }) => {
      return (
        <ThemeProvider theme={theme}>
          <MUIButton
            color="primary"
            variant={variant}
          >
            {children}
          </MUIButton>
        </ThemeProvider>
      )
    }
    

    I am trying to figure out how I can do this at a global level in Storybook. This is the first component I have built out called Button. So I want to be able to have the theme in an external file, and have the ThemeProvider coming in at a higher level so I don't have to wrap each component. Hope that makes sense, and if anyone has any ideas.

  • Guilherme Felipe Reis
    Guilherme Felipe Reis over 3 years
    For the new version of Storybook v6 uses like that export const decorators = [<ThemeProvider theme={muiTheme}>{story()}</ThemeProvider>]
  • Elnur
    Elnur over 2 years
    Yes, the only solution that worked! Thanks!
  • Eliav Louski
    Eliav Louski over 2 years
    only Emotion10ThemeProvider wrapper was needed in the preview.js in order to make this work in my case (no need to change /main.js config file)
  • Eliav Louski
    Eliav Louski over 2 years
    Yes, you are absolutely right! this is the only solution that truly propagates down MUI V5 theme(including RTL support)
  • hotpink
    hotpink over 2 years
    Thank you so much!
  • Sabrina Tolmer
    Sabrina Tolmer about 2 years
    Thanks! Not .storybook/main.js configuration was needed it. The Emotion10ThemeProvider was enough for my case to work.
  • dsvanlani
    dsvanlani about 2 years
    This worked for me with MUI v5
  • Nika
    Nika about 2 years
    Thanks! This worked for me with the latest versions of Mui and Storybook! You are a lifesaver!