'How to theme Material UI inside Storybook
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.
Solution 1:[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:[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:[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/
Solution 4:[4]
This works for me with react-router and mui V5
my preview.js =>
import React from 'react';
import { addDecorator } from '@storybook/react';
import { MemoryRouter } from 'react-router';
import { ThemeProvider } from '@mui/material/styles';
import { ThemeProvider as Emotion10ThemeProvider } from 'emotion-theming';
import customTheme from '../src/theme/index';
addDecorator((story) => (
<Emotion10ThemeProvider theme={customTheme}>
<ThemeProvider theme={customTheme}>
<MemoryRouter initialEntries={['/']}>{story()}</MemoryRouter>
</ThemeProvider>
</Emotion10ThemeProvider>
));
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Hugo |
Solution 2 | David Fou |
Solution 3 | Yodacheese |
Solution 4 | Yassine Soltani |