Fragmented Thought

Using your Material (MUI) themes in Storybook



Lance Gliser

After a recent talk on Storybook 7 for the React ATX community, I wondered about how I could make it even easier. A couple weeks after, I booked a bit of time and tinkered with the built in concepts of Storybook 7 Backgrounds feature. They advertise it as 'backgrounds', but you can much more with a tiny recipe.


By default, Backgrounds simply change the color of the background. You can make it white, black, pink, etc. It's just a hex color and name. Our first step then is to loop through all our MUI themes, making background entries:

In your .storybook/preview.tsx file, you'll need to update the default export:

import type { Preview } from "@storybook/react"; import dark from "../src/themes/dark"; import light from "../src/themes/light"; const preview: Preview = { parameters: { // More on how to position stories at: // layout: "fullscreen", // TODO not having any effect.. backgrounds: { // Load them by hand, or make a nice loop if you wish values: [ { // MUI themes don't have `displayName` by default. // Just add it to the interface to carry on. name: prismLightLocal.displayName, value: prismLightLocal.palette.background.default, }, { name: prismDarkLocal.displayName, value: prismDarkLocal.palette.background.default, }, ], // Ensure a default is set, so you avoid type errors reading from undefined! default: prismLightLocal.displayName, }, // Your other configurations }, }; export default preview;

Theme decorator

From there, you can add your own Decorator to hook up your Theme Provider.

This can be done in your .storybook/preview.tsx file as well to provide the global integration.

import type { Decorator, StoryFn } from "@storybook/react"; import { CssBaseline, ThemeProvider } from "@mui/material"; // Create a theme decorator const withTheme: Decorator = (Story, context) => { // Determine which theme should be provided from your earlier // imports by matching on the background color const theme = context.globals.backgrounds?.value === prismDarkLocal.palette.background.default ? prismDarkLocal : prismLightLocal; // Ship it! return ( <> <ThemeProvider theme={theme}> <CssBaseline enableColorScheme /> <Story /> </ThemeProvider> </> ); }; // Then setup your own set of decorators as you need export const decorators: Decorator[] = [ (Story: StoryFn) => ( <MemoryRouter> <HelmetProvider> <Story /> </HelmetProvider> </MemoryRouter> ), // And ensure our new decorator is included withTheme, ];

That's it. Now instead of just 'light' and 'dark' generically, you'll have your entire theme applied swapping components on the fly as you need to level up your team's velocity.

Huge credit to the Storybook folks for making this so much easier in 7!