見出し画像

StorybookでUIのドキュメントを書いてみよう

本記事は、Japan Digital Design Advent Calendar 2023 の13日目の記事になります。


三菱UFJフィナンシャル・グループ(以下MUFG)の戦略子会社であるJapan Digital Design(以下JDD)のTDD Dev2でフロントエンドエンジニアをしている村山です。

JDDのTDD Dev2では、銀行の方が業務で扱う類似相場検索ツールテクニカル指標勝率ランキングといったシステムを開発しています。

本記事では、開発中に課題となったUIのドキュメントについてStorybookを利用して書いてみたのでそれについてご紹介させていただきます。


環境

  • react v18.2.0

  • vite v5.0.0

  • storybook v7.6.3

  • scaffdog v3.0.0

説明しないこと

今回以下の方法は説明しないため、必要があれば公式のドキュメントなどを御覧ください。

  • Viteなどでのプロジェクトの初期化方法

  • Storybookの初期化方法

手順

Storybook 6ではドキュメントはStoryごとに書くようになっていましたが、今回対象のStorybook 7ではコンポーネントごとにドキュメントを書くように変更となっています。
またドキュメントの記載方法も自動で生成してくれるAutodocs機能と自分でMDXファイルを書いていくパターンの2通りありますが、今回は前者のAutodocsを使った方法をご紹介します。

1. Autodocsの有効化

まず今回使うAutodocsを有効化するために、.storybook/main.ts(JavaScriptならmain.js)に以下のようにautodocs: trueを追記します。

import type { StorybookConfig } from "@storybook/react-vite";

const config: StorybookConfig = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
  addons: [],
  framework: {
    name: "@storybook/react-vite",
    options: {},
  },
  docs: {
    // 👇 ここを追記
    autodocs: true,
  },
};
export default config;

7系ではおそらくStorybook初期化時にautodocs: "tag"が設定されているかと思います。その場合は各コンポーネントのMetaデータにtags: ['autodocs']を追加することでドキュメント生成をオプトインできます。今回紹介のautodocs: trueではグローバルにドキュメント生成が有効になるため、tags: ['autodocs']は不要となります。

2. JSDocでのドキュメントコメントの記載

1のAutodocs有効化だけでもDocsページは作られある程度ドキュメントしては機能するのですが、コンポーネントやpropsに細かい説明がないため各説明をJSDocのドキュメンテーションコメント(/** コメント */)で追記していきます。
以下は簡単なButtonコンポーネントを例に書いています。

import React from 'react';

interface ButtonProps {
  /**
   * ボタンに表示されるテキスト
   */
  label: string;
  /**
   * ボタンの背景色
   */
  color?: string;
  /**
   * ボタンをクリックした時の処理
   */
  onClick: () => void;
}

/**
 * シンプルなボタンコンポーネント
 */
export const Button: React.FC<ButtonProps> = ({
  label,
  color = "#1ea7fd",
  onClick,
}) => {
  return (
    <button
      type="button"
      style={{
        fontSize: "14px",
        padding: "8px 16px",
        border: "none",
        borderRadius: "3em",
        cursor: "pointer",
        display: "inline-block",
        lineHeight: 1,
        color: 'white',
        backgroundColor: color,
      }}
      onClick={onClick}
    >
      {label}
    </button>
  );
};

コンポーネントの説明はもちろんですが、Storybookの各Storyにも同様に説明が記載ができるためこちらも同様に記載していきます。

import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';

const meta: Meta = {
  title: 'Example/Button',
  component: Button,
};

export default meta;
type Story = StoryObj<typeof meta>;

/**
 * デフォルトカラーのボタン
 */
export const Default: Story = {
  args: {
    label: 'DefaultButton',
    onClick: () => {},
  },
};

/**
 * 赤色のボタン
 */
export const Red: Story = {
  args: {
    label: 'RedButton',
    color: 'red',
    onClick: () => {},
  },
};

3. Storybookへの反映の確認

ドキュメントの追記が終わりましたStorybookを起動して内容を確認します。
上記の内容をStorybook上で確認すると、まずDocsのページが表れます。

次にDocsをクリックすると以下のようにコンポーネント、props、Storyに説明が入った状態のドキュメントが表示されます。

これでStorybookのリッチなUI上にUIのドキュメントを生成することができました。

おまけ

便利なStorybookですが、コンポーネントを作成する際にStrorybookのファイル含め一式まとめて生成したい事があるかと思います。
そんなときはscaffdogを使うことでMarkdown形式で一式生成するジェネレーターを書くことができます。
例えば以下のようなディレクトリ構造のコンポーネントを作成したいと思います。(今回はテストファイルなどは除いていますが適宜追加して貰えればと思います)

このような構成の場合、scaffdog初期化後に.scaffdogディレクトリに以下のようなマークダウンファイルを置くことで生成が可能になります。
(詳細な使い方はscaffdogのドキュメントを見ていただければと思います)

---
name: 'component'
root: '.'
output: 'src/'
ignore: ['.']
questions:
  name: 'Please enter a component name.'
  story:
    confirm: 'Do you need a story?'
    initial: true
---

# Variables

- component_name: {{ inputs.name | pascal }}
- props_name: {{ component_name + 'Props' }}


# `components/{{ component_name }}/index.ts`

```typescript
export * from './{{ component_name }}';

```

# `components/{{ component_name }}/{{ component_name }}.tsx`

```typescript
import React from 'react';

type {{ props_name }} = {};

/**
 * Describe the component.
 */
export const {{ component_name }}: React.FC<{{ props_name }}> = ({}) => {
  return <div></div>;
};

```

# `{{ !inputs.story && '!' }}components/{{ component_name }}/{{ component_name }}.stories.tsx`

```typescript
import type {
  Meta, StoryObj,
} from '@storybook/react';
import { {{ component_name }} } from './{{ component_name }}';

const meta: Meta = {
  title: '{{ 'Components' + '/' + component_name }}',
  component: {{ component_name }},
}

export default meta

/**
 * Describe the story.
 */
export const Default: StoryObj<typeof {{ component_name }}> = {
  args: {},
}

```

まとめ

シンプルな内容ですがStorybookでのドキュメント生成の紹介でした。
よりドキュメントの内容をカスタマイズしてみたい場合は、冒頭に少し紹介したMDXを使った方法も試してみてください。
自分たちもまだこのドキュメントを使った開発を回せてはいないので、もっと良いやり方などあればぜひコメントなどでフィードバックを頂ければと思います。

以上、「StorybookでUIのドキュメントを書いてみよう」でした。
最後までご覧いただきありがとうございました。


Japan Digital Design株式会社では、一緒に働いてくださる仲間を募集中です。カジュアル面談も実施しておりますので下記リンク先からお気軽にお問合せください。

この記事に関するお問い合わせはこちら

Technology & Development Division
Mitsuhiro Murayama

参考