Styling Addon: configure styles and themes in Storybook

Shaun Evening
Storybook

--

How to set up styling tools with Storybook is a common question from the community. Though there are a ton of articles describing how (and we’ve written some ourselves), these aren’t always up to date, which causes unnecessary headaches and a setup process of trial and error.

To reduce these issues and simplify the setup process, we’re introducing the Styling Addon. It’s a framework-agnostic solution that works with Tailwind, Material UI, Chakra, Emotion, Styled-components, SASS, and PostCSS.

  • 🌎 Provide global styles
  • 🎨 Add theme providers
  • 🌗 Switch between themes in a click
  • ‼️ Override the theme for a story
Switching between light and dark mode using the Styling Addon’s theme switcher

Getting started

There are different versions available depending on whether you’re using Storybook 6 or Storybook 7.

# For Storybook 6
yarn add -D @storybook/addon-styling

# For Storybook 7
yarn add -D @storybook/addon-styling@next

Once installed, open up your .storybook/main.js file and add @storybook/addon-styling into the addons array.

module.exports = {
stories: [
"../stories/**/*.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)",
],
addons: [
"@storybook/addon-essentials",
"@storybook/addon-styling",
],
};

Provide global styles

If your global styles are defined in CSS files, you can import your stylesheets in the .storybook/preview.js file. Storybook will load any files imported here on every story render.

// .storybook/preview.js
import '../src/styles.css'; // Your local styles
import 'bootstrap/dist/css/bootstrap.min.css'; // Styles from node_modules

UI libraries for React (like Material UI) provide their global styles as a React component. To make this component available for your component stories, you can use the included withThemeFromJSXProvider decorator.

// .storybook/preview.js
import { CssBaseline } from '@mui/material';
import { withThemeFromJSXProvider } from '@storybook/addon-styling';

/* snipped for brevity */
export const decorators = [
withThemeFromJSXProvider({
GlobalStyles: CssBaseline,
}),
];

Add theme providers

React libraries often ship with a ThemeProvider component, a wrapper that shares your theme with its children. withThemeFromJSXProvider will take that provider and your theme configuration and wrap all of your stories for you.

// .storybook/preview.js
import { CssBaseline, ThemeProvider } from "@mui/material";
import { withThemeFromJSXProvider } from "@storybook/addon-styling";
import { myCustomTheme } from "../src/theme.js";

/* snipped for brevity */
export const decorators = [
withThemeFromJSXProvider({
themes: { myCustomTheme },
Provider: ThemeProvider,
GlobalStyles: CssBaseline,
}),
];

Switch between themes

Users have come to expect multiple themes — such as dark mode and high contrast — for their favourite apps. You’ll need to see how your stories look in each one. The Styling Addon handles this for you! 🎉

When you configure withThemeFromJSXProvider with more than one theme, it will add a dropdown menu to the Storybook toolbar that lets you switch between each theme in a click.

// .storybook/preview.js
import { CssBaseline, ThemeProvider } from "@mui/material";
import { withThemeFromJSXProvider } from "@storybook/addon-styling";
import {
myCustomTheme,
myCustomDarkTheme,
myCustomHighContrastTheme,
} from "../src/theme.js";

/* snipped for brevity */

export const decorators = [
withThemeFromJSXProvider({
themes: {
light: myCustomTheme,
dark: myCustomDarkTheme,
highContrast: myCustomHighContrastTheme,
},
defaultTheme: "light",
Provider: ThemeProvider,
GlobalStyles: CssBaseline,
}),
];

Not using React or JSX? No problem!

A large portion of Storybook users don’t use JSX or React. If that’s you: don’t worry! We have you covered! The Styling Addon includes two more decorators for folks that change themes based on a parent class or data attribute.

For example, Tailwind lets you activate dark mode when a parent element has the .dark class. In this case, add your theme classes to withThemeFromClassName and choose a default theme to set up the theme selector.

// .storybook/preview.js
import { withThemeByClassName } from "@storybook/addon-styling";
import "../src/tailwind.css";

export const decorators = [
withThemeByClassName({
themes: {
light: "light",
dark: "dark",
},
defaultTheme: "light",
}),
];

If you’re using a tool like Bootstrap that sets its theme with a data-attribute, you can give withThemeFromDataAttribute your themes, a default theme, and the name of the attribute to set up the theme selector.

// .storybook/preview.js
import { withThemeByDataAttribute } from "@storybook/addon-styling";
import "bootstrap/dist/css/bootstrap.min.css";

export const decorators = [
withThemeByDataAttribute({
themes: {
light: "light",
dark: "dark",
},
defaultTheme: "light",
attributeName: "data-bs-theme",
}),
];

Override the theme

If you’re using a tool like Chromatic, you might have snapshots of your stories with different themes applied. To do this, set parameters.theming.themeOverride to the name of the theme you want to be applied for your story.

Switching to the “Primary Dark” story for the story component overrides the theme to dark

Configure CSS processing tools

Css processing tools extend the capabilities of CSS so that you can get more out of your styles with less code. That’s why we’ve added options to include Sass and Postcss in your Storybook’s webpack config for you. If you’re using Storybook 7 with Vite or the Next.js framework, this is already handled for you.

Sass

To replace @storybook/preset-sass which is deprecated, the Styling Addon offers configuration options for Sass.

Start by installing a few extra dependencies:

yarn add -D style-loader sass sass-loader resolve-url-loader

Then update the @storybook/addon-styling configuration in .storybook/main.js to include sass:

// .storybook/main.js
module.exports = {
stories: ["../stories/**/*.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-essentials",
{
name: "@storybook/addon-styling",
options: {
sass: {
implementation: require("sass"),
},
},
},
],
};

Now you can import your Sass files into .storybook/preview.js.

// .storybook/preview.js
import '../src/styles.scss';

Need a more advanced configuration for Sass? Learn about the full API for options.sass in the addon documentation.

PostCSS

To replace @storybook/preset-postcss, which is deprecated, addon-styling offers configuration options for PostCSS. Update the @storybook/addon-styling configuration in .storybook/main.js to include postCss and it will use the options set in your postcss.config.js file.

// .storybook/main.js
module.exports = {
stories: ["../stories/**/*.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-essentials",
{
name: "@storybook/addon-styling",
options: {
postCss: true,
},
},
],
};

If you need Postcss 8 for Tailwind, make sure to install it, then pass that implementation along in the settings:

// .storybook/main.js
module.exports = {
stories: ["../stories/**/*.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)"],
addons: [
"@storybook/addon-essentials",
{
name: "@storybook/addon-styling",
options: {
postCss: {
implementation: require("postcss"),
},
},
},
],
};

With that configured, you can now import your Tailwind CSS file into .storybook/preview.js and any changes to your code will rebuild your CSS along with your stories.

To learn about the full API for options.postCss, take a look at the addon documentation.

Wrapping up

The Styling Addon simplifies configuring Storybook for all your styling needs, like global styles, theme providers, and CSS processing tools. The addon allows switching between themes and overriding themes for specific stories and the best part is that it’s framework agnostic, helping you to deliver your best work in whichever way you choose!

While this simplifies configuration for your styling tools, we want to make it even easier! Starting with Tailwind, we’re looking to share codemods for the most popular libraries that help set up this configuration automatically for you so that you can get straight to writing your stories.

Are you excited about the Styling Addon? Are there other Storybook integrations you want to see? Tweet at @storybookjs or reach out on the Storybook Discord Server! We can’t wait to meet you 🤩

https://upscri.be/f/d42fc0

--

--