🎨

【React】StorybookにMUIのカスタムテーマを反映させる

2022/03/26に公開

MUIのカスタムテーマをStorybookに反映させようとした際に、themeProviderで囲むだけでは反映されず、設定を変更する必要があったので共有です。

前提

環境

package.json
package.json
{
  "name": "mui-storybook-sample",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
  },
  "dependencies": {
    "@emotion/react": "^11.8.2",
    "@emotion/styled": "^11.8.1",
    "@mui/material": "^5.5.2",
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "devDependencies": {
    "@babel/core": "^7.17.8",
    "@storybook/addon-actions": "^6.4.19",
    "@storybook/addon-essentials": "^6.4.19",
    "@storybook/addon-interactions": "^6.4.19",
    "@storybook/addon-links": "^6.4.19",
    "@storybook/react": "^6.4.19",
    "@storybook/testing-library": "^0.0.9",
    "@types/react": "^17.0.33",
    "@types/react-dom": "^17.0.10",
    "@vitejs/plugin-react": "^1.0.7",
    "babel-loader": "^8.2.4",
    "typescript": "^4.5.4",
    "vite": "^2.8.0"
  }
}
環境構築ログ
# react, typescript
$ npm create vite@latest mui-storybook-sample -- --template react-ts
$ cd mui-storybook-sample && npm i

# MUI install
$ npm install @mui/material @emotion/react @emotion/styled

# Storybook install
$ npx -p @storybook/cli sb init

MUIのカスタムテーマ

今回はprimaryカラーをデフォルトの青から緑に変更しています。

/src/theme.ts
import { createTheme } from "@mui/material/styles";
import { green } from "@mui/material/colors";

export const theme = createTheme({
  palette: {
    primary: {
      main: green[500],
    },
  },
});

App.tsx

App.tsxは今回の本質ではないので無くても良いのですが、カスタムテーマの反映方法として載せておきます。
MUIでカスタムテーマを反映するには、ThemeProviderコンポーネントで表示領域を囲む必要がります。

/src/App.tsx
import Button from "@mui/material/Button";
import { ThemeProvider } from "@mui/material/styles";

import { theme } from "./theme";

function App() {
  return (
    <ThemeProvider theme={theme}>
      <div className="App">
        <Button variant="contained">Contained</Button>
      </div>
    </ThemeProvider>
  );
}

export default App;

プレビューすると以下のようにプライマリーカラーが緑になっていることが確認できます。

Storybookにカスタムテーマを反映させる

ストーリーを作る

MUIのボタンを表示するために、Button.stories.tsxを作成します。

/src/stories/Button.stories.tsx
import { ComponentStory, ComponentMeta } from "@storybook/react";

import Button from "@mui/material/Button";

export default {
  title: "MUI/Button",
  component: Button,
} as ComponentMeta<typeof Button>;

const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
Primary.args = {
  children: "Button",
  color: "primary",
  variant: "contained",
};

Button.stories.tsxを作成したら以下コマンドでプレビューを表示します。

$ npm run storybook

このように、Buttonコンポーネントは表示されますが、カスタムテーマが反映されていないので、カスタムテーマを反映させる設定を追加していきます。

カスタムテーマを反映させる

Storybookの設定を追加するには.storybookディレクトリにあるpreciew.jsmain.jsを修正します。

preview.jsにThemeProviderを記述

Storybookのデコレータという機能を使って、Storybookのプレビュー全体をMUIのThemeProviderコンポーネントで囲みます。

/.storybook/preview.js
+ import { ThemeProvider } from "@mui/material/styles";
+ import { theme } from "/src/theme";

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

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};

MaterialUI (v4系)まではこれでカスタムテーマが反映されていたのですが、MUI(v5系)からは更にmain.jsに設定を加える必要があります。

main.jsの設定を変更

featuresというプロパティのemotionAliasfalseにします。

/.stories/main.js
module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: "@storybook/react",
+ features: {
+   emotionAlias: false,
+ },
};

StorybookのライブサーバをCtrl+Cでキャンセルし、再度npm run storybookを実行すると、以下のようにカスタムテーマが反映されたプレビューが表示されます。

Discussion