🧃

ChakraUIのTheming使いにくいので別の方法で導入!

2022/09/08に公開

始めに

今回はChakra UIの公式にあるThemingが使いにくいので別の方法で実装!!!!
あ、喧嘩売ってるわけではありません。

以下ChakraUI公式
https://chakra-ui.com/

公式通りの問題点と対応方法

公式記載の方法だと以下のような問題があるような気がして、今回別の実装方法で試しました。

問題点1 - 同一のオブジェクトを参照している

前提として、Themeはオブジェクトを参照しているだけのシンプルな構造になります。

標準のThemingイメージ

標準では1つのオブジェクトから「ライトモードの時はどれを使う」「ダークモードの時はどれを使う」のようなイメージで使う情報を指定して使用します。

official

今回カスタムしたThemingイメージ

参照元のオブジェクトをライトテーマ、ダークテーマ、〇〇テーマ...のように複数のオブジェクトを作成して参照元を切り替える方法です。

メリット

  1. Themeオブジェクトを切り替えるため実装側ではThemeを意識することなく実装することができます。
  2. デザインシステムを構築する際にConfigファイルをデザインチームと共有することによって、Configを元にThemeオブジェクトを入れ替えるだけでThemeの更新が完了します。

custom

問題点2 - テーマが増加した時の対応

ライトモード、ダークモードしかできないのかなぁと思ったらできそうかも。。。
複数Themeが増えるたびにコンポーネント側での変更が多そうなのであまり実用的ではないかもしれないのでデメリットをまとめました。

実装方法(やってみてはない)

  1. colorModeを'light' | 'dark'から追加したいモードを追加する
  2. toggleThemeを修正する(実装方法はしらべてません...)
  3. 完了!

デメリット

  1. 追加のたびに修正範囲が大きい
text.ts
// light | dark の2種類の場合
const color = colorMode === "dark" ? "gray.800" : "white"

// light | dark | other の3種類に増えた場合
const color = colorMode === "dark" ? "black" :
       colorMode === "light" ? "white" :
       "gray"

実装

1. themeファイルを作成

※定義するThemeの属性は統一する必要があります。

lightTheme.ts
ライトテーマ
import { extendTheme } from "@chakra-ui/react";
export const lightTheme = extendTheme({
  colors: {
    primary: {
	100: "#111111",
	300: "#333333",
	600: "#666666"
    }
  },
});
darkTheme.ts
ダークテーマ
import { extendTheme } from "@chakra-ui/react";
export const lightTheme = extendTheme({
  colors: {
    primary: {
	100: "#666666",
	300: "#999999",
	600: "#CCCCCC"
    }
  },
});

2. providerを作成

※createContext,useContext,useReducerを使用した例です。

provider.tsx

import React from "react";
import { ReactNode } from "react";
import { ChakraProvider } from "@chakra-ui/react";

export type Props = {
  children: ReactNode;
};

export const ChakraUiProvider: React.FC<Props> = ({ children }) => {
  const themeContext = useContext(ThemeContext);
  return (
      <ChakraProvider theme={themeContext.store.theme}>
          {children}
      </ChakraProvider>;
  )
};

3. componentで使用

※createContext,useContext,useReducerを使用した例です。
以下のようにボタンでTheme切り替え処理をつけてみると、Themeが切り替わるたびにボタンの背景色が変わることを確認できます。

TestPage.tsx
// カスタムバージョン

import React from "react";
import { Button, Box } from "@chakra-ui/react";

export const TestPage: React.FC = () => {
  const themeContext = useContext(ThemeContext);
  return (
    <Box>
      <Button
        bg={"primary.100"}
	onClick={()=>themeContext.dispatch("toggleTheme")}
      >
        ToggleThemeButton
      </Button>
    </Box>
  )
};

TestPage.tsx
// 公式
export const TestPage: React.FC = () => {
  const { toggleColorMode } = useColorMode()
  const bg = useColorModeValue('red.500', 'red.200')

  return (
    <Box>
      <Button
        bg={bg}
	onClick={toggleColorMode}
      >
        ToggleThemeButton
      </Button>
    </HStack>
  )
}

おまけ: Themeをカスタムしたら補完が出ない時の対応

ChakraUIは便利なCLIを準備してくれているのでそれを使えば問題ない!

以下参考
https://chakra-ui.com/docs/styled-system/advanced-theming#theme-typings

  1. パッケージインストール
yarn add --dev @chakra-ui/cli
npm install -D @chakra-ui/cli
  1. Themeファイルの更新
    以下のコマンドで "export theme", "export default theme"をしているファイルを指定すると、指定したthemeの型(Dict<>)に従ってnode_modules内の型定義ファイルが更新されます。
npx chakra-cli tokens <path/to/your/theme.(js|ts)>

最後に

割とこのThemingの方法は気に入っているのでおすすめ。
以下のような流れでデザインシステムの構築にも割と利便性がある。
FigmaTokenでConfigを生成→GitHubで共有→フロントエンドのConfigを更新→Themeを更新

あ、フロントエンドエンジニアではないので多めにみてください💦

なんか他にいい方法があったり、パフォーマンス的な観点ではみていないので問題あればご教授ください!!

以上!

Discussion