【v2とv3を比較しながら】Chakra UI v3のコンポーネントカスタマイズ方法

第3チームのフロントエンドを中心に業務をしている赤星です。

弊社のOfferBoxでは一部に Chakra UI を利用しているのですが、先日Chakra UIのバージョンをv2からv3にアップデートした際にとてもアップデート作業に苦労しました。 Chakra UIのv3は大幅な破壊的変更があり、公式リファレンスもどのようにコンポーネントをカスタマイズするのか各コンポーネントごとに解説しなくなったのでここで詳しく説明していこうと思います。

コンポーネントカスタマイズ方法の変更(v2→v3)

まず、Chakra UIのコンポーネントをカスタマイズする前に前提部分に変更があるので解説します。

ChakraProviderの変更

Chakra UIを利用する際、ChakraProviderコンポーネントを挿入すると思います。この際v2では以下のように書きましたが、

import { ChakraProvider } from '@chakra-ui/react';

export function Root() {
    <ChakraProvider theme={data}>
         {/* 中身 */}
    </ChakraProvider>
}

v3では以下のように書きます。

import { ChakraProvider } from '@chakra-ui/react';

export function Root() {
    <ChakraProvider value={data}>
         {/* 中身 */}
    </ChakraProvider>
}

themeがvalueになりました。

extendThemeからcreateSystemへ

カスタムしたいデータの一覧を定義する方法も変わりました。v2は以下のように書きましたが、

import { extendTheme } from '@chakra-ui/react';

export const data = extendTheme({
   // ここにカスタムしたいデータの詳細を書く
});

v3では以下のように書きます。

import { createSystem, defaultConfig } from '@chakra-ui/react';

export const data = createSystem(defaultConfig, {
    // ここにカスタムしたいデータの詳細を書く
})

extendThemeがcreateSystemになり、第一引数にdefaultConfigを差し込みます。

コンポーネントのカスタマイズ方法

さて、本題です。まずv2でコンポーネントをカスタマイズしたい際は以下のように書きました。

import { extendTheme } from '@chakra-ui/react';

export const data = extendTheme({
   components: {
       Button: Buttonコンポーネントのカスタマイズデータ,
       CheckBox: Checkboxコンポーネントのカスタマイズデータ,
       Switch: Switchコンポーネントのカスタマイズデータ,
       Badge: Badgeコンポーネントのカスタマイズデータ,
   }
});

ですが、v3では以下のように書きます。

import { createSystem, defaultConfig } from '@chakra-ui/react';

export const data = createSystem(defaultConfig, {
    theme: {
      recipes: {
        button: Buttonコンポーネントのカスタマイズデータ,
        badge: Badgeコンポーネントのカスタマイズデータ,
      },
      slotRecipes: {
        checkbox: Checkboxコンポーネントのカスタマイズデータ,
        switch: Switchコンポーネントのカスタマイズデータ,
      },
    },
})

themeの中にrecipesとslotRecipesを定義してそこにそれぞれのコンポーネントのカスタマイズデータを入れます。 ではこのrecipesslotRecipesには何の違いがあるのでしょうか。

recipesとslotRecipes

結論から述べると複数の部品から構成されているコンポーネントがslotRecipes、そうでないものがrecipesに分類されます。

v2のCheckboxコンポーネントの図を見るとわかりやすいかなと思います。

v2では

  • control
  • icon
  • container
  • label

の部品からCheckboxのコンポーネントが構成されていることがわかります。こういったコンポーネントがv3ではslotRecipesに入ります。

v2におけるCheckboxのコンポーネントの構造(Chakra UI公式から引用)

見分け方

ですが、残念なことにv3の公式リファレンスではv2の公式リファレンスのように対象コンポーネントがどのような部品で構成されているのか一切言及されていません。なので一見するとどれがslotRecipesでどれがrecipesなのかがわかりません。

ですが見分け方はちゃんと存在します。それは...

Chakra UIのソースコードを直接読みに行くことです

といってもそこまで難しくはありません。先ほどと同じようにCheckboxコンポーネントで解説します。 まず、公式リファレンスにあるv3のCheckboxコンポーネントのページにアクセスし、GitHubのアイコンがあるRecipeのリンクをクリックします。

ここをクリック

ここにアクセスすると対象コンポーネントのデフォルトのカスタマイズ設定のソースコードが表示されます。

defineSlotRecipeと書いているのでこれはslotRecipeであることがわかる

大事なのは5行目です。defineSlotRecipeと書かれている部分がありますね。

ここの箇所にdefineSlotRecipeと書いてあればslotRecipes、defineRecipeと書いてあればrecipesに入れましょう。

recipesのカスタマイズ

ここではButtonコンポーネントで解説します。v2では以下のように書きました。

import { defineStyleConfig } from '@chakra-ui/react';

export const button = defineStyleConfig({
    baseStyle: {
      fontWeight: 'bold',
    },
    variants: {
      primary: {
        bg: 'blue.500',
        color: 'white',
      },
    },
    sizes: {
        sm: {
            bg: 'blue.800',
        }
    },
    defaultProps: {
      variant: 'basic',
    },
});

ですが、v3では以下のように書きます。

export const button = defineRecipe({
    base: {
      fontWeight: 'bold',
    },
    variants: {
      variant: {
        solid: {
          bg: 'blue.500',
          color: 'white',
        },
      },
      size: {
        sm: {
          bg: 'blue.800',
        },
      },
    },
    defaultVariants: {
      variant: 'solid',
    },
});

色々変わりました。主に変わった点としては

  • 全てに適用させたいスタイルを書くbaseStyleがbaseに
  • variantごとのスタイルがvariantsの下に直接書くのではなく、variantsの下にvariantを定義し、その中に書くように(solidがvariant名)
  • 大きさごとのスタイルを書くsizesがvariantsの下にsizeを定義し、その中に記載するように(複数形から単数系になったので注意)
  • 対象コンポーネントのデフォルトの値を定義するdefaultPropsがdefaultVariantsに

となります。

ちなみに余談ですがButtonコンポーネントはv2からv3のアップデートに伴いvariantの名前が変わっているので注意が必要です。

slotRecipesのカスタマイズ

ここではCheckboxコンポーネントで解説します。v2では以下のように書きました。

import { defineStyleConfig } from '@chakra-ui/react';

export const companyCheckBoxStyle = () =>
  defineStyleConfig({
    baseStyle: {
      control: {
        borderColor: 'gray.500',

        _disabled: {
          backgroundColor: 'gray.400',
          border: 'none',

          _checked: {
            backgroundColor: 'gray.400',
          },
        },
      },
    },
    sizes: {
      sm: {
        label: {
          fontSize: 14,
        },
      },
    },
  });

ですが、v3では以下のように書きます。

import { defineSlotRecipe } from '@chakra-ui/react';

export const companyCheckBoxStyle = () =>
  defineSlotRecipe({
    slots: ['root', 'control', 'label'],
    base: {
      control: {
        borderColor: 'gray.500',

        _disabled: {
          backgroundColor: 'gray.400',
          border: 'none',

          _checked: {
            backgroundColor: 'gray.400',
          },
        },
      },
    },
    variants: {
      size: {
        sm: {
          label: {
            fontSize: '14px',
          },
        },
      }
    },
  });

こちらも変わりました。主に変わった点としては

  • recipesと同様の変更点
  • カスタマイズしたい部品をslotsの配列に列挙しておく

となります。

さらに部品名もコンポーネントによっては名称が変わっています。ですが、残念なことに先ほど記述したようにそのコンポーネントがどのような部品で構成されているのか公式リファレンスに一切明記されていません。

ではどのようにして部品名を知るのでしょうか?

主に2つ方法があります。それらを解説します。

1. Chakra UIの元になっているArk UIのリファレンスを読みに行く

引き続きCheckboxコンポーネントで解説します。

Chekboxコンポーネントの公式リファレンスにアクセスした後、「Ark」と書かれているリンクをクリックします。

ここをクリック

するとArk UIのCheckboxの公式リファレンスのページが表示されます。

Ark UIのCheckboxの公式リファレンスのページ

それを少し下にスクロールすると、Anatomyという箇所があるのでそこに図解付きで部品名とその位置が示されています。

図解付きで部品名とその位置が示されている

しかし、AlertコンポーネントやNativeSelectコンポーネント等一部のコンポーネントは残念なことにこの方法で確認することができません。

2. Chakra UIのソースコードを直接読みに行く

こちらもソースコードを直接読みに行くといってもそこまで難しくありません。ここではAlertコンポーネントで解説します。

Chakra UIには各コンポーネントの部品名を定義してあるファイルがあり、そのファイル(下記ページ)にアクセスします。

github.com

アクセスしたらcreateAnatomyの引数に"alert"と書いてある箇所を探します。

ここにalertの構成部品が書いてある

その後にあるpartsの引数に書かれている文字列の一覧が構成部品の名前です。

ちなみにですが、この部品名が具体的にコンポーネントのどの位置にあたるかは実装部分を読みに行かない限り、(私が探した限りでは)どこにも明記されていないので名前から大体察してください

色テーマごとのカスタマイズ方法

一部コンポーネントは色テーマがあり、例えばBadgeコンポーネントでは以下のように色を変えることができます。

Badgeコンポーネント

ここではBadgeコンポーネントでその色テーマのカスタマイズ方法を解説します。v2では以下のように書きました。

import { defineStyleConfig } from '@chakra-ui/react';

export const companyBadgeStyle = () =>
  defineStyleConfig({
    variants: {
      solid: (props) => ({
        ...(props.colorScheme === 'gray' && {
          bg: 'gray.700',
        }),
        ...(props.colorScheme === 'blue' && {
          bg: 'blue.500',
        }),
      }),
    },
  });

ですが、v3では以下のように書きます。

import { defineRecipe } from '@chakra-ui/react';

export const companyBadgeStyle = () =>
  defineRecipe({
    variants: {
      variant: {
        solid: {},
      },
    },
    compoundVariants: [
      {
        variant: 'solid',
        colorPalette: 'gray',
        css: {
          bg: 'gray.700',
        },
      },
      {
        variant: 'solid',
        colorPalette: 'blue',
        css: {
          bg: 'blue.500',
        },
      },
    ],
  });

個人的にはこちらはv3になってからわかりやすくなったと感じています。

あらかじめvariantにcompoundVariantsで使うvariant名を定義しておき、compoundVariantsに設定を書き込むという流れです。

compoundVariantsに書かれている一部を抜き出すと、下記はvariantがsolidでcolorPalette(色テーマ)がgrayの場合のCSS設定ということになります。

{
    variant: 'solid',
    colorPalette: 'gray',
    css: {
      bg: 'gray.700',
    },
},

余談ですが、v2からv3のアップデートに伴い、そのコンポーネントの色テーマを設定する時に使うprops名がcolorSchemeからcolorPaletteに変更されていることに注意してください。

さいごに

本当にv2からv3になってから仕様が色々変わりました。他にもDividerコンポーネントがなくなったり、Tableコンポーネントの書き方が変わったり、ModalコンポーネントがDialogコンポーネントに名前が変わったりと挙げたらキリがないくらいには変わっています。

今回のv3へのアップデートは本当に大変だったなと感じつつ筆を置かせて頂こうかなと思います。

ⓒ i-plug,inc. All Rights Reserved.