📒

storybookを理解する

2022/01/05に公開約7,000字

この記事ではReact, Typescriptをベースにstorybookの全体像に触れていきます。

「storybook、名前は聞いたことある」というレベル感の人に対して、実務でstorybookを使う上での下地を作ることが目的です。そのため、「細かい」と判断した部分は割愛させてもらってます。(あくまで下地)

基本的には公式ドキュメントがベースになっていますので、詳しい説明は公式ドキュメントを確認してください。

storybookとは

storybookとはUIのカタログを作るツールで、2022年現在、フロントエンド開発において必要不可欠です。

各componentのUIやpropsに応じた挙動の確認、component単位でドキュメントを用意することを可能にしてくれます。

導入方法

コマンドを打ちましょう。

npx sb init

下記コマンドでpreview画面が起動します。

yarn storybook

そうするとインストールした時に作成された雛形がpreviewで表示されるでしょう。

storyの書き方

storybookにcomponentを登録していくには、storyを記述する必要があります。
stories.js | ts | jsx | tsx | mdxの拡張子に設定することで、ファイルはstoryとして認識されます。
また、これらは開発環境のみでプロダクション環境ではbundleされません。

Component Story Format(CSF)

Component Story Formatは推奨されているstoryの書き方です。ESmoduleをベースとして記述している書き方でstory fileはdefault export か named exportから構成されています。(ESmoduleについての説明は割愛)

CSFの詳しい概要はこちら。

具体的な書き方

最初にstoryのmetadataをdefault exportする必要があります。

export default {
  title: 'Button',
  component: Button,
} as ComponentMeta<typeof Button>;

titleをui-componens/Buttonみたいにすると階層を表現できます。

その下に各componentを記述していきます。

// 小文字だとButton配下にファイルが作成されない。
// titleとcomponentの名前を同じにしたい場合、小文字にするとよい。
export const button: ComponentStory<typeof Button> = () => <Button />;

// ベースcomponentを元にcomponentをButton配下に表示させたい時に変数の命名を変更させる。
export const basic: ComponentStory<typeof Button> = () => <Button />;
export const primary: ComponentStory<typeof Button> = () => <Button />;

propsに応じてcomponentを複数表示するには

templateとしてbindするとPropsに応じたcomponentを表示しやすくなります。

↓このようなpropsを必要とするcomponentがあるとします。

button.tsx
import React from "react";
type Props = {
  text: string;
};

const Button: React.VFC<Props> = ({ text }) => {
  return <button style={{ padding: "5px" }}>{text}</button>;
};

export default Button;

↓bindしてあげる。

Button.stories.tsx
/* eslint-disable react/react-in-jsx-scope */
import Button from "./Button";
import { ComponentStory, ComponentMeta } from "@storybook/react";

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

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

export const Primary = Template.bind({});
Primary.args = { text: "this is Primary" };

export const Secondary = Template.bind({});
Secondary.args = { text: "this is Secondary" };

そうすると、画像のようにstorybookからinputで表示されるでしょう。
もちろんこれは編集することができ、propsを適当な値にして表示を気軽に確認できます。
"storybookのcomponentbind"

イベントの書き方

さらにaddonでActionをつかってonClickを定義してあげましょう。
propsにonClickを含めます。

Button.tsx
const Button: React.VFC<Props> = ({ text, onClick }) => {
  return (
    <button style={{ padding: "5px" }} onClick={onClick}>
      {text}
    </button>
  );
};

export default Button;

@storybook/addon-actionsをmain.jsでaddonの配列に追加したのちに、先ほどのstoryにpropsを追記します。

Button.stories.tsx
import { action } from "@storybook/addon-actions";
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
Primary.args = { text: "this is Primary", onClick: action("clicked") };

export const Secondary = Template.bind({});
Secondary.args = { text: "this is Secondary", onClick: action("clicked") };

そうするとbuttonをクリックした際にactionが走り、下ペインから確認することができます。
storybookのOnclick Action

parameaterを使う

metadataの中にparameterを入れることでstoryのトップレベルに設定を追記することができます。
公式ドキュメントと同じように設定してみましょう。
背景色を設定することができることが確認できます。

Button.stories.tsx
export default {
  title: "example/Button",
  component: Button,
  parameters: {
    backgrounds: {
      values: [
        { name: "red", value: "#f00" },
        { name: "green", value: "#0f0" },
        { name: "blue", value: "#00f" },
      ],
    },
  },
} as ComponentMeta<typeof Button>;

"storybook背景色設定"

decoratorsを使う

metadataの中にdecoratorsを追記することで、storyがレンダリングされる際に任意の要素でwrapすることができます。
公式ドキュメントでは下記のようにdiv要素でmarginを設定しています。

decorators: [
  (Story) => (
    <div style={{ margin: '3em' }}>
      <Story />
    </div>
  ),
],

decoratorは範囲によって記述する場所が異なるので、公式ドキュメントを参照してください。

Docsの書き方

各componentに応じたdocumentを書くことができます。documentの書き方(表示のされ方)はmetadataから設定します。

component及びsubcomponent

metadataにて、componentとsubcomponentを設定するとドキュメントでpropsがtable形式で表示されます。

export default {
  title: "example/Buttons",
  component: ButtonGroup,
  subcomponents: { Button },
} as Meta;

"ButtonGroupとButton"

mdx

mdxを使ってmarkdownライクに記述することもできます。
詳しくは公式ドキュメントを見て下さい。

docsのカスタマイズ

ドキュメントページに表示される項目を自分でカスタマイズすることもできます。

Button.stories.tsx
export default {
  title: 'Button',
  component: Button,
  parameters: {
    docs: {
      // ここで表示される項目、その順番などを変更することができる
      page: () => (
        <>
          <Title>タイトル</Title>
          <Subtitle>サブタイトル</Subtitle>
          <Primary />
          <ArgsTable story={Button} />
          <Description markdown={markdown} />
        </>
      ),
    },
  },
};


const markdown = `
# markdownn
> testtest
`;

Buildをする

個人的に下記オプションを覚えておけばいいと思います。

  • -sで静的ファイルを設定
  • -oで出力先ディレクトリを設定

npx sb initでプロジェクトを立ち上げた場合はpackage.jsonに初期buildコマンドが追加されているので、自分のプロジェクトに応じて修正してください。

また、buildしたファイルをpublishする際には、vercel,Netlify,S3が使えます。公式ドキュメントを確認してみてください。

tests

chromaticへhosting及びvisual test

UIのvisual testについては以前記事にしたので、そちらを参照してください。

https://zenn.dev/kyo9bo/articles/9909ba89c42a77

a11y test

yarn add --dev @storybook/addon-a11yでアクセシビリティのaddonを追加してください。
main.jsの設定に追記して、yarn storybookをすれば、preview画面から確認することができます。

細かい設定方法は公式ドキュメントを確認してください。

interaction test

user eventをstoryに組み込み確認したい場合は、@storybook/testing-libraryを使いましょう。

ここでは詳しく触れません。公式ドキュメントを確認してください。
ドキュメントではFormでemailとpasswordを入力させて、UIの確認をしています。

各種設定方法

必要に応じて、公式ドキュメントを参照しましょう。
細かいので、ここでは割愛します。

storybook公式の情報

公式のブログがあります。こちらをみていれば最新の情報はキャッチアップできます。

https://storybook.js.org/blog/

CSF3.0というコンセプトは魅力的なのでチェックするといいかもしれません。

まとめ

奥が深いので軽く全体を抑えてから、その他addonや細かい設定に手を出すと良さそうです。
また、今後storybookがプラットフォームとなって様々なツールが連携し、フロントエンドの開発が発展するでしょう。

参考文献

Storybook: UI component explorer for frontend developers

GitHubで編集を提案

Discussion

ログインするとコメントできます