O hirunewani blog

Storybookでサイドバーのラベルにタグを付ける

Created at

Storybookでサイドバーのラベルにタグを付ける方法を紹介する。ラベルにタグを表示することで、コンポーネントの状態などを分かりやすくできる。

Storybookで次のような表示が出来るようにする。

alt text

tagsからラベルにタグを付ける

各Storyでtagsに特定のタグが含まれていればラベルにタグを表示するようにする。

次の例では、deprecatedというタグが含まれていれば、非推奨を表すタグを表示するようにしている。

// .storybook/manager.jsx
import { addons } from "@storybook/manager-api";
import startCase from "lodash/startCase.js";
import Tag from "../your-components/tag";

addons.setConfig({
  sidebar: {
    renderLabel: (item, api) => {
      // item.typeがrootの場合、apiはundefined
      const data = api?.getCurrentStoryData()
      if (item.depth === 1) {
        return(
            <span>
                {startCase(item.name)}
                {data?.tags.includes("deprecated") && (
                    <Tag variant="warning">Deprecated</Tag>
                )}
            </span>
        );
      }
      return  startCase(item.name)
    }
});

この例では、item.depthを見ることで一階層目にのみタグが付くようにしている。これを行わない場合、tagsは継承されていくため、そのラベル以下の階層全てのラベルに同じタグが付いてしまう。

tagsの付与方法

tagsは、次のように指定することが出来る。

// grid.stories.tsx
// ...
export default {
  title: "Layout/Grid",
  component: Grid,
  tags: ["deprecated"],
} satisfies Meta<typeof Grid>;
// ...

注意点

この方法は、とてもタグとtagsが紐づいており、とても素直な実装に思えるかもしれないが、次のことに注意が必要。

  • タグが被ると意図しない副作用が発生する。
    • tagsには、暗黙的にdev/test/autodocs/play-fnなどStorybookから様々なタグが自動的に付与される。
    • これらをStorybookやそのAddonが見ているため、副作用が起こりえる。
  • タグの取得に利用しているapiを使うことが想定されていないように思える。
    • apiの型がanyになっている。
    • ドキュメントにもほぼ言及がない。

Storiesファイルのタイトル名からタグを付ける

tagsapiの利用が不安であれば、タイトルの文字列をパースするくらいしか方法が残されていないように思う。

次のようにタイトルへタグを付ける。

// grid.stories.tsx
// ...
export default {
  title: "Layout/Grid#Deprecated",
  component: Grid,
} satisfies Meta<typeof Grid>;
// ...

次のようにしてタイトルをパースして利用する。

// .storybook/manager.jsx
import { addons } from "@storybook/manager-api";
import startCase from "lodash/startCase.js";
import Tag from "../your-components/tag";

addons.setConfig({
  sidebar: {
    renderLabel: (item) => {
        if (item.depth === 1) {
            if (item.name.endsWith("#Deprecated")){
                const name = item.name.replace("#Deprecated", "");
                return(
                    <span>
                        {startCase(name)}
                        <Tag variant="warning">Deprecated</Tag>
                    </span>
                );
            }
        }
        return  startCase(item.name)
    }
});

注意点

この方法では、Docsタブに#Deprecatedの文字列が表示されてしまう。 これが許容できなければ、apiから生えているsetメソッドで更新できると思うが、であればtagsを利用した方がいいだろう。