使用環境
MacOS BigSur(11.5.2) / VScode(1.59.1) / Node.js (16.1.1) / "@chakra-ui/icons": "^1.0.15" / "@chakra-ui/react": "^1.6.6"
はじめに
最近、Next.js(React)を使ったプロジェクトでChakra UIを使用しています。
Chakra UIに関する記事がQiitaではあまり見られないので、学びになったことをちょこちょこ投稿していくことにしました。
今回は、タイトルの通りChakra UIを使ったダークモードの実装方法について書いていきます。
驚くほど簡単だったので、Reactの基礎が分かっている人なら10分以内で実装できてしまうと思います。
では早速、やっていきましょう。
実装
まず初めに基本の流れだけざっと説明しておくとこんな感じになります
- 準備
- Chakra UIのインポート
- Providerのセットアップ - useColorModeのセットアップ
- コンポーネントで使用する(以上)
+α ダークモード/適用時のスタイルをグローバルで指定する方法
+α 初期設定をする方法(CRA /Next.jsの場合)
1. 準備
・Chakra UIのインストール
導入していない方は、まずはここから始めましょう。既に終わっている方はスキップして2から始めてください。
#npmの場合
npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
#yarnの場合
yarn add @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^4
・Providerのセットアップ
Create React Appの場合
Rootとなっているコンポーネントファイルで以下のように設定していきます。
import * as React from "react"
// 1. import `ChakraProvider` component
import { ChakraProvider } from "@chakra-ui/react"
function App({ Component }) {
// 2. Use at the root of your app
return (
<ChakraProvider>
<Component />
</ChakraProvider>
)
}
Next.jsの場合
pages/_app.js か pages/_app.tsx(TypeScriptを導入している際はこちら)で以下のように設定していきます。
import { ChakraProvider } from "@chakra-ui/react"
function MyApp({ Component, pageProps }) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
)
}
export default MyApp
2. useColorModeのセットアップ
ダークモード実装を簡単にできるuseColorMode
というHooksと、アイコンに使用する IconButton
、MoonIcon
、SunIcon
をインポートする。(お好みに応じてreact-iconsを使用するのもOK)
import { IconButton, useColorMode } from '@chakra-ui/react'
import { MoonIcon, SunIcon } from '@chakra-ui/icons'
あとは、useColorModeをこの様に定義する。このuseColorModeというのは現在のカラーモードの状態をcolorModeで保持して、toggleColorModeで切り替えもしてくれる機能があります。
const { colorMode, toggleColorMode } = useColorMode()
3. コンポーネントで使用する
あとはインポートしたIcconButtonというコンポーネントに記述していきます。ポイントはiconプロパティを使用していることと、その中でcolorModeが'light'
かどうかで、<MoonIcon />
か <FaSun />
を出し分けしている点です。
ちなみにcolorModeは、デフォルトで'light'
か'dark'
というstringのみを保持する様になっています。(color-mode.utils.d.ts内での宣言: export declare type ColorMode = "light" | "dark";
)
<IconButton
// _focus={{_focus: "none"}} //周りの青いアウトラインが気になる場合に消す方法
mb={10}
aria-label="DarkMode Switch"
icon={colorMode === 'light' ? <MoonIcon /> : <FaSun />} //自分の好みでSunアイコンはreact-iconsを使用しています
onClick={toggleColorMode}
/>
この画像のように、Chakra UIで提供しているほとんどのコンポーネントはデフォルトでダークモードに対応してcolorを変化してくれます。
By default, most of Chakra's components are dark mode compatible. In some scenario, you might need to make your component respond to color mode.
もし自分で切り替え時の色を設定したい場合は上記に併せて useColorModeValue
が使えます。(以下は[公式サイト][2]から引っ張ってきたコードです。)
useColorModeValue
は2つの引数を取ることができ、1つ目の引数が'light'
に対応し、2つ目の引数が'dark'
に対応します。
import { useColorModeValue, useColorMode } from '@chakra-ui/react'
function StyleColorMode() {
const { toggleColorMode } = useColorMode()
const bg = useColorModeValue("red.500", "red.200")
const color = useColorModeValue("white", "gray.800")
return (
<>
<Box mb={4} bg={bg} color={color}>
This box's style will change based on the color mode.
</Box>
<Button size="sm" onClick={toggleColorMode}>
Toggle Mode
</Button>
</>
)
}
ちなみに自分で実装してみた場合はこんな感じです。
import { useColorModeValue, useColorMode } from '@chakra-ui/react'
const { colorMode, toggleColorMode } = useColorMode()
const bgGradient = useColorModeValue("linear(to-l, blue.400, #7928CA,#FF0080)", "linear(to-r, blue.400, #7928CA,#FF0080)"
<Heading
mb={8}
bgClip="text"
bgGradient={bgGradient}
fontSize="6xl"
fontWeight="extrabold"
>
NEXT TODO
</Heading>
どうでしょうか?密かにタイトルのグラデーション色が反転してますね。
(うん、わかりづらいですね。)
+α グローバルでダークモード/ライトモード時のスタイルを指定する
グローバル適用するにはCustomize themeが使えるんでしたね。ここではCustomize themeについての詳しい説明は省きます。気になる方は[公式Doc][3]みてみてください。
ポイントはpropsとして別のコンポーネントで定義したcolorMode
を受け取って、colorを変化させている点です。
import { extendTheme } from '@chakra-ui/react'
// NB: Chakra gives you access to `colorMode` and `theme` in `props`
export const theme = extendTheme({
styles: {
global: (props) => ({
'html, body': {
fontSize: 'sm',
color: props.colorMode === 'dark' ? 'white' : 'gray.600',
lineHeight: 'tall',
padding: 0,
margin: 0,
},
a: {
color: props.colorMode === 'dark' ? 'white' : 'gray.600',
textDecoration: 'none',
},
}),
}
}
rootとなるコンポーネントで導入した <ChakraProvider>
にthemeをインポートしてpropsとして渡すのをお忘れなく。
import { ChakraProvider } from '@chakra-ui/react'
import { theme } from 'src/theme/theme'
function MyApp({ Component, pageProps }: AppProps) {
return (
<ChakraProvider theme={theme}>
<Component {...pageProps} />
</ChakraProvider>
)
}
export default MyApp
+α 初期設定をする方法(CRA /Next.jsの場合)
先程のthemeにconfigでinitialColorMode
とuseSystemColorMode
を定義しextendThemeに渡します。
// theme.js
import { extendTheme } from "@chakra-ui/react"
const config = {
initialColorMode: "light", // ColorModeの初期値を設定
useSystemColorMode: false, // システムで導入しているカラーモードを適用するかどうか(falseは適用しない場合)
}
const theme = extendTheme({ config })
export default theme
あとは全体にこの設定を読み込ませていきます。
・Create React Appの場合
themeをインポートしてColorModeScript
をindex.jsファイルに記述します。
// index.js
import ReactDOM from "react-dom"
import App from "./App"
import theme from "./theme"
ReactDOM.render(
<>
<ColorModeScript initialColorMode={theme.config.initialColorMode} />
<App />
</>,
document.getElementById("root"),
)
・Next.jsの場合
themeをインポートしてColorModeScript
を_document.jsファイルに記述します。
import { ColorModeScript } from "@chakra-ui/react"
import NextDocument, { Html, Head, Main, NextScript } from "next/document"
import bodyTheme from "src/theme/theme"
export default class Document extends NextDocument {
render() {
return (
<Html lang="en">
<Head />
<body>
<ColorModeScript initialColorMode={bodyTheme.config.initialColorMode} />
<Main />
<NextScript />
</body>
</Html>
)
}
}
最後に
こんなに簡単にダークモードを実装できるなんて思ってもいなかったです。
画面を見る時間が増えている現代ではダークモード導入の必要性も高まっているので、今後も活用していきます。
また、実装していたらChakra UIがなくともReactのHooksで実装できそうだなと思ったので、時間がある時にアレンジを加えて試してみたいと思います。
p.s.
最後の初期設定のやり方自体は理解できたのですが、どうしても自分のプロジェクトにinitialColorMode
を導入することができませんでした。systemColorMode
はtrueにした際に適用されたのでこちらはうまくできているみたいなので、ColorMode Scriptでの読み込みがうまくできてないのかなと疑って、Customize Themeでbodyにあてていた設定を消したり、色々試したりましたがダメみたいでした。もし理由がわかる方がいたら教えていただきたいです。
ソースコード: https://github.com/hirooutdoor/next-todo2
・src/theme/theme.ts
・pages/_document.js
参考資料
Chakra UI公式ドキュメント [useColorMode][1]
[1]:https://chakra-ui.com/docs/features/color-mode#usecolormode
[2]:https://chakra-ui.com/docs/features/color-mode#usecolormodevalue
[3]:https://chakra-ui.com/docs/theming/customize-theme