[React + Typescript] emotion の Theming 機能を使って複数のTheme切り替えを実装してみた
やりたいこと
emotion の ThemeProvider を使って自前で定義した複数の Theme の切り替えを実装してみました。
コードの量が多かったため全体のコードは CodeSandbox で公開しています。
emotion とは
glam, glamor, styled-component, glamorous といった既存のライブラリから影響を受けて作られた CSS in JS ライブラリです。
書き方もstyled-componentによく似ており、styled-component でできることは emotion でも大体できそうという印象を受けました。
新規プロジェクトの作成
React + typescript の雛形を作成します。
npx create-react-app emotion_sample --template typescript
emotion の導入
プロジェクトのルートディレクトリへ移動し、以下のモジュールをインストールします。
必要なのは@emotion/react
と@emotion/styled
の2つです。
cd emotion_sample yarn add -D @emotion/react @emotion/styled
Theme を定義する
theme/theme.ts
に Theme を複数定義します。
theme/theme.ts
export const pink = { fonts: { mainFont: "Avenir Next, sans-serif", subFont: "Hira Kaku Pro N, sans-serif", textFont: "Hiragino Sans", numberFont: "Avenir Next, sans-serif", }, colors: { mainColor: "#64363C", subTextColor: "#8E354A", lineColor: "#E6E5E4", backgroundColor: "#F8C3CD", titleBackgroudColor: "#F8F4F4", accentColor: "#EB7A77", stageColor: "#CB1B45", }, }; export const yellow = { fonts: { mainFont: "Times New Roman", subFont: "Garamond", textFont: "Tahoma", numberFont: "Times New Roman", }, colors: { mainColor: "#5B622E", subTextColor: "#8D742A", lineColor: "#E6E5E4", backgroundColor: "#DCB879", titleBackgroudColor: "#EFBB24", accentColor: "#212121", stageColor: "#90B44B", }, }; export const sky = { fonts: { mainFont: "Impact", subFont: "Tahoma, sans-serif", textFont: "Impact", numberFont: "Impact", }, colors: { mainColor: "#6c756b", subTextColor: "#8D8D8D", lineColor: "#E6E5E4", backgroundColor: "#F3F4F5", titleBackgroudColor: "#96C5F7", accentColor: "#212121", stageColor: "#4D565D", }, };
emotion Theme の型を Override する
src/
下に@types
フォルダを切り、先ほど定義した Theme の型を@types/theme.d.ts
ファイルに定義して emotion の Theme 型を拡張します。
@types/theme.d.ts
import '@emotion/react' declare module '@emotion/react' { interface Theme { fonts: Fonts colors: Colors } } interface Colors { mainColor: string subTextColor: string lineColor: string backgroundColor: string titleBackgroudColor: string accentColor: string stageColor: string } interface Fonts { mainFont: string subFont: string textFont: string numberFont: string }
これで IDE 上での型補完が有効になります。
ThemeProvider を追加する
Theme を反映するためにApp.tsx
にThemeProvider
を追加します。
App.tsx
import React from "react"; import {pink} from "./themes/theme"; import {ThemeProvider} from "@emotion/react"; function App() { return ( <ThemeProvider theme={pink}> <div className="App">Hoge</div> </ThemeProvider> ); } export default App;
Component で要素を参照する
ここまでで Theme の設定が完了したのであとはコンポーネント内で Theme の値を参照してください。
const H1 = styled.h1` font-weight: 500; font-family: ${theme.fonts.mainFont}; font-size: 28px; text-align: center; color: ${theme.colors.accentColor}; margin-top: 8px; margin-bottom: 0; `;
あとがき
今回初めて CSS in JS ライブラリを利用してみましたが要素の Styling においては特に嵌ることもなくすでにある CSS の知識だけで書き進めることができました。emotionの機能や書き方などの詳細についてはしばらく使ってみて知見がたまったらまたまとめようと思います。