T-CREATOR

Emotion チートシート:css/styled/Global/Theme の即戦力スニペット 20

Emotion チートシート:css/styled/Global/Theme の即戦力スニペット 20

React 開発でスタイリングを効率化したいとき、Emotion は強力な味方になります。CSS-in-JS ライブラリとして、TypeScript との相性も良く、動的なスタイリングやテーマ管理が簡単に実現できるんです。

この記事では、Emotion の主要な 4 つの機能(cssstyledGlobalTheme)に絞って、実務ですぐ使える 20 個のスニペットを厳選してご紹介します。初心者の方でもコピペで試せるよう、それぞれのコードには丁寧なコメントを付けていますので、ぜひ最後までお読みください。

Emotion スニペット早見表

以下の表で、この記事で紹介する 20 個のスニペットを一覧できます。

#カテゴリスニペット概要主な用途
1css基本的なインラインスタイル単一要素への簡易スタイル適用
2css擬似クラス(hover)の活用ホバー時のスタイル変更
3cssメディアクエリの実装レスポンシブデザイン
4css配列形式での複数スタイル結合スタイルの再利用・組み合わせ
5cssprops に応じた動的スタイル条件分岐によるスタイル制御
6styledstyled.div の基本構文コンポーネント化されたスタイル
7styledprops を受け取る動的スタイルプロパティベースのスタイル変更
8styledstyled 継承と拡張既存 styled コンポーネントの再利用
9styledas prop による要素の切り替えHTML 要素の動的変更
10styledネストされたセレクタ子要素への直接スタイル適用
11Globalグローバルスタイルの設定リセット CSS やベーススタイル
12Globalフォント・カラーの全体統一サイト全体のタイポグラフィ設定
13Globalカスタムスクロールバーブラウザ UI 要素のカスタマイズ
14ThemeThemeProvider の基本設定テーマオブジェクトの提供
15Themeテーマ値を参照する styledデザイントークンの活用
16Themeテーマ値を参照する css関数形式でのテーマ利用
17Themeダークモード切り替えテーマの動的変更
18Themeブレークポイントのテーマ管理レスポンシブ設定の一元化
19複合css と styled の組み合わせ柔軟なスタイル管理
20複合Theme と Global の統合パターンアプリ全体のスタイル基盤構築

背景

近年の React 開発では、コンポーネント単位でスタイルを管理する CSS-in-JS アプローチが主流になってきました。従来の CSS ファイルによる管理では、グローバルな名前空間の衝突やスタイルの依存関係が複雑になりがちでしたが、CSS-in-JS を使えば、JavaScript の中でスタイルを完結させられます。

Emotion は、そうした CSS-in-JS ライブラリの中でも特に高いパフォーマンスと柔軟性を誇り、多くのプロジェクトで採用されています。React だけでなく Next.js や Gatsby などのフレームワークとも相性が良く、TypeScript の型推論もしっかり効くため、開発体験が非常に優れているんですね。

以下の図は、Emotion が React コンポーネントとどのように連携し、最終的にブラウザで描画されるかの全体フローです。

mermaidflowchart LR
  developer["開発者"] -->|JSX記述| component["Reactコンポーネント"]
  component -->|Emotion APIを呼び出し| emotion["Emotion<br/>ライブラリ"]
  emotion -->|CSS生成| styleNode["<style>タグ"]
  styleNode -->|DOMに挿入| browser["ブラウザ<br/>描画"]

上図のように、Emotion は React コンポーネント内で呼び出され、動的に CSS を生成して DOM に反映させます。この仕組みにより、props や state に応じたリアルタイムなスタイル変更が可能になるわけです。

課題

Emotion は非常に強力ですが、学習コストもそれなりにあります。公式ドキュメントは充実しているものの、初めて触れる方にとっては「どの API をどのシーンで使えば良いのか」が分かりにくいことも。

また、Emotion には主に 2 つの記法(css prop とstyledコンポーネント)があり、さらにグローバルスタイルやテーマ管理の機能も備わっているため、それぞれの使い分けを理解しないと、コードが統一感を失ってしまう恐れがあります。

以下の図は、Emotion を使う際によくある課題と、それに対する解決の流れを示したものです。

mermaidflowchart TD
  start["Emotion導入"] --> challenge1["記法の選択に迷う"]
  challenge1 --> solution1["css vs styled\nの使い分け理解"]
  solution1 --> challenge2["グローバルスタイルの管理"]
  challenge2 --> solution2["Global\nコンポーネント活用"]
  solution2 --> challenge3["テーマ管理・ダークモード"]
  challenge3 --> solution3["ThemeProvider\nの導入"]
  solution3 --> goal["統一感のある\nスタイル管理"]

このように、Emotion の各機能を段階的に理解し、適切に使い分けることで、保守性の高いスタイリングが実現できます。

解決策

この記事では、Emotion の主要な 4 つの機能に焦点を当て、それぞれの特徴と使い分けを明確にします。

css プロパティ

css prop は、JSX 要素に直接スタイルを適用する最もシンプルな方法です。@emotion​/​reactパッケージのcss関数を使い、テンプレートリテラルまたはオブジェクト形式でスタイルを記述します。インラインで書けるため、簡単なスタイル調整や一時的なスタイル上書きに適しています。

styled コンポーネント

styledは、スタイル付きの React コンポーネントを生成する API です。@emotion​/​styledパッケージから提供され、styled.divstyled.buttonのように、HTML 要素をラップした再利用可能なコンポーネントを作成できます。複雑なスタイルや props に応じた動的な変更が必要な場合に威力を発揮します。

Global コンポーネント

Globalコンポーネントは、アプリケーション全体に適用されるグローバルスタイルを定義するために使います。リセット CSS やベースフォント、カラー設定などをまとめて記述でき、<Global styles={...} ​/​>の形でアプリのルートに配置するのが一般的です。

ThemeProvider

ThemeProviderは、テーマオブジェクトを React の Context API を通じて配下のコンポーネントに提供する仕組みです。カラーパレット、フォントサイズ、ブレークポイントなどのデザイントークンを一元管理し、ダークモード切り替えなどの機能も簡単に実装できます。

以下の図は、これら 4 つの機能の関係性と役割分担を示しています。

mermaidflowchart LR
  theme["ThemeProvider\nテーマ定義"] -->|テーマ値を提供| global["Global\nグローバルスタイル"]
  theme -->|テーマ値を参照| css_prop["css prop\nインラインスタイル"]
  theme -->|テーマ値を参照| styled_comp["styled\nコンポーネント"]
  global -->|ベーススタイル適用| app["アプリケーション全体"]
  css_prop -->|簡易スタイル適用| component1["個別コンポーネント"]
  styled_comp -->|再利用可能スタイル| component2["個別コンポーネント"]

上図のように、ThemeProviderが中心となってテーマ値を各機能に提供し、Globalがアプリ全体の土台を作り、cssstyledが個別コンポーネントのスタイリングを担当します。

具体例

それでは、実際に使える 20 個のスニペットを順番にご紹介していきます。それぞれのコードはコピペで動作するよう、必要なインポート文も含めて記載しています。

1. css prop の基本的なインラインスタイル

css prop を使って、要素に直接スタイルを適用する最もシンプルな例です。

インポート

typescript/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';

スタイル定義と適用

typescript// シンプルな色と余白の指定
const boxStyle = css`
  background-color: #f0f0f0;
  padding: 16px;
  border-radius: 8px;
`;

コンポーネントでの使用

typescriptexport const SimpleBox = () => {
  // css propに先ほど定義したスタイルを渡す
  return (
    <div css={boxStyle}>これはシンプルなボックスです</div>
  );
};

このように、css関数でスタイルを定義し、css prop に渡すだけで簡単にスタイルが適用されます。

2. css prop で擬似クラス(hover)を活用

ホバー時のスタイル変更も、css prop の中に直接記述できます。

スタイル定義(hover 含む)

typescriptconst hoverStyle = css`
  background-color: #3498db;
  color: white;
  padding: 12px 24px;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s ease;

  // hover時のスタイル
  &:hover {
    background-color: #2980b9;
  }
`;

コンポーネントでの使用

typescriptexport const HoverButton = () => {
  return (
    <button css={hoverStyle}>ホバーしてください</button>
  );
};

&:hoverのように、Sass 風のネスト記法が使えるのが Emotion の特徴です。

3. css prop でメディアクエリを実装

レスポンシブデザインのためのメディアクエリも、スタイル定義の中に含められます。

スタイル定義(メディアクエリ含む)

typescriptconst responsiveStyle = css`
  font-size: 14px;
  padding: 8px;

  // タブレット以上(768px以上)
  @media (min-width: 768px) {
    font-size: 16px;
    padding: 12px;
  }

  // デスクトップ以上(1024px以上)
  @media (min-width: 1024px) {
    font-size: 18px;
    padding: 16px;
  }
`;

コンポーネントでの使用

typescriptexport const ResponsiveText = () => {
  return (
    <p css={responsiveStyle}>
      画面幅に応じてサイズが変わります
    </p>
  );
};

メディアクエリを直接書けるため、コンポーネント単位でレスポンシブ対応が完結します。

4. css prop で配列形式のスタイル結合

複数のスタイルを配列で渡すことで、再利用性を高められます。

基本スタイルと追加スタイルの定義

typescript// 基本スタイル
const baseStyle = css`
  padding: 16px;
  border-radius: 4px;
`;

// 追加スタイル
const primaryStyle = css`
  background-color: #3498db;
  color: white;
`;

配列形式でスタイルを結合

typescriptexport const CombinedBox = () => {
  // 配列で複数のスタイルを適用
  return (
    <div css={[baseStyle, primaryStyle]}>
      結合されたスタイル
    </div>
  );
};

配列の後ろに指定したスタイルが優先されるため、上書きのルールも明確です。

5. css prop で props に応じた動的スタイル

props の値に応じてスタイルを切り替える例です。

型定義

typescripttype AlertBoxProps = {
  type: 'info' | 'warning' | 'error';
  children: React.ReactNode;
};

動的スタイル生成関数

typescript// typeに応じて背景色を変更する関数
const getAlertStyle = (type: AlertBoxProps['type']) => css`
  padding: 16px;
  border-radius: 4px;
  background-color: ${type === 'info'
    ? '#d1ecf1'
    : type === 'warning'
    ? '#fff3cd'
    : '#f8d7da'};
  color: ${type === 'info'
    ? '#0c5460'
    : type === 'warning'
    ? '#856404'
    : '#721c24'};
`;

コンポーネントでの使用

typescriptexport const AlertBox = ({
  type,
  children,
}: AlertBoxProps) => {
  return <div css={getAlertStyle(type)}>{children}</div>;
};

このように、関数を使って props に応じたスタイルを動的に生成できます。

6. styled.div の基本構文

styledコンポーネントは、スタイル付きの React コンポーネントを生成します。

インポート

typescriptimport styled from '@emotion/styled';

styled コンポーネントの定義

typescript// styled.divでスタイル付きdiv要素を作成
const StyledBox = styled.div`
  background-color: #ecf0f1;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`;

コンポーネントでの使用

typescriptexport const BoxComponent = () => {
  return (
    <StyledBox>これはstyledコンポーネントです</StyledBox>
  );
};

styled.divのように、HTML 要素名をメソッドチェーンで指定するだけで、スタイル付きコンポーネントが作れます。

7. styled component で props を受け取る動的スタイル

styled コンポーネントに props を渡して、スタイルを動的に変更する例です。

型定義

typescripttype ButtonProps = {
  primary?: boolean;
};

props を受け取る styled コンポーネント

typescript// propsに応じて背景色を変更
const StyledButton = styled.button<ButtonProps>`
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
  background-color: ${(props) =>
    props.primary ? '#3498db' : '#95a5a6'};
  color: white;
  transition: opacity 0.2s ease;

  &:hover {
    opacity: 0.8;
  }
`;

コンポーネントでの使用

typescriptexport const DynamicButton = () => {
  return (
    <>
      <StyledButton primary>プライマリボタン</StyledButton>
      <StyledButton>セカンダリボタン</StyledButton>
    </>
  );
};

<ButtonProps>で型を指定し、props.primaryで props の値を参照します。

8. styled component の継承と拡張

既存の styled コンポーネントを継承して、スタイルを追加できます。

基本となる styled コンポーネント

typescript// 基本ボタンスタイル
const BaseButton = styled.button`
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  font-size: 16px;
  cursor: pointer;
`;

BaseButton を継承して拡張

typescript// BaseButtonのスタイルを引き継ぎ、追加スタイルを適用
const PrimaryButton = styled(BaseButton)`
  background-color: #3498db;
  color: white;

  &:hover {
    background-color: #2980b9;
  }
`;

コンポーネントでの使用

typescriptexport const ExtendedButton = () => {
  return <PrimaryButton>拡張されたボタン</PrimaryButton>;
};

styled(BaseButton)のように、既存の styled コンポーネントをラップすることで、スタイルの再利用が簡単になります。

9. as prop による要素の切り替え

as prop を使うと、同じスタイルのまま別の HTML 要素に切り替えられます。

styled コンポーネントの定義

typescript// 汎用的なテキストスタイル
const StyledText = styled.p`
  font-size: 16px;
  color: #2c3e50;
  line-height: 1.6;
`;

as prop で要素を切り替え

typescriptexport const FlexibleText = () => {
  return (
    <>
      {/* pタグとして描画 */}
      <StyledText>これは段落です</StyledText>

      {/* spanタグとして描画 */}
      <StyledText as='span'>これはspan要素です</StyledText>

      {/* h2タグとして描画 */}
      <StyledText as='h2'>これは見出しです</StyledText>
    </>
  );
};

as="span"のように指定するだけで、スタイルはそのままに要素だけ変更できるため、とても便利です。

10. styled component でネストされたセレクタ

styled コンポーネント内で子要素に直接スタイルを適用する例です。

ネストされたセレクタを含む styled コンポーネント

typescript// 親要素のスタイルと、子要素へのネストスタイル
const Card = styled.div`
  padding: 20px;
  background-color: white;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);

  // 子要素のh3にスタイルを適用
  h3 {
    margin-top: 0;
    color: #2c3e50;
  }

  // 子要素のpにスタイルを適用
  p {
    color: #7f8c8d;
    line-height: 1.6;
  }
`;

コンポーネントでの使用

typescriptexport const NestedCard = () => {
  return (
    <Card>
      <h3>カードタイトル</h3>
      <p>カードの説明文がここに入ります。</p>
    </Card>
  );
};

Sass のようなネスト記法で、子要素のスタイルを親コンポーネント内に記述できます。

11. Global コンポーネントでグローバルスタイルを設定

アプリ全体に適用されるリセット CSS やベーススタイルを定義します。

インポート

typescriptimport { Global, css } from '@emotion/react';

グローバルスタイルの定義

typescript// リセットCSSとベーススタイル
const globalStyles = css`
  // ボックスサイジングをborder-boxに統一
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  // bodyの基本スタイル
  body {
    font-family: -apple-system, BlinkMacSystemFont,
      'Segoe UI', Roboto, 'Helvetica Neue', Arial,
      sans-serif;
    line-height: 1.6;
    color: #333;
  }
`;

アプリのルートに配置

typescriptexport const App = () => {
  return (
    <>
      {/* グローバルスタイルを適用 */}
      <Global styles={globalStyles} />
      {/* 以下、アプリのコンテンツ */}
      <div>アプリケーションの内容</div>
    </>
  );
};

<Global styles={...} ​/​>をルートに配置するだけで、サイト全体にスタイルが適用されます。

12. Global でフォント・カラーの全体統一

グローバルスタイルで、フォントやカラーを統一する例です。

グローバルスタイルの定義

typescriptconst globalTypography = css`
  :root {
    // CSS変数でカラーを定義
    --color-primary: #3498db;
    --color-secondary: #2ecc71;
    --color-text: #2c3e50;
    --color-background: #ecf0f1;
  }

  body {
    font-family: 'Helvetica Neue', Arial, sans-serif;
    font-size: 16px;
    color: var(--color-text);
    background-color: var(--color-background);
  }

  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    color: var(--color-primary);
    font-weight: 600;
  }

  a {
    color: var(--color-primary);
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }
`;

アプリのルートに配置

typescriptexport const App = () => {
  return (
    <>
      <Global styles={globalTypography} />
      <div>統一されたタイポグラフィが適用されます</div>
    </>
  );
};

CSS 変数(--color-primaryなど)を使うことで、後からテーマ切り替えもしやすくなります。

13. Global でカスタムスクロールバー

ブラウザのスクロールバーをカスタマイズする例です。

グローバルスタイルの定義

typescriptconst customScrollbar = css`
  // Webkit系ブラウザ(Chrome、Safari)のスクロールバー
  ::-webkit-scrollbar {
    width: 12px;
  }

  ::-webkit-scrollbar-track {
    background-color: #f1f1f1;
  }

  ::-webkit-scrollbar-thumb {
    background-color: #888;
    border-radius: 6px;

    &:hover {
      background-color: #555;
    }
  }
`;

アプリのルートに配置

typescriptexport const App = () => {
  return (
    <>
      <Global styles={customScrollbar} />
      <div style={{ height: '200vh' }}>
        スクロールしてスクロールバーを確認してください
      </div>
    </>
  );
};

Webkit 系ブラウザでカスタムスクロールバーが表示されます。

14. ThemeProvider の基本設定

テーマオブジェクトを定義し、ThemeProviderで配下のコンポーネントに提供します。

インポート

typescriptimport { ThemeProvider } from '@emotion/react';

テーマオブジェクトの定義

typescript// テーマの型定義
type Theme = {
  colors: {
    primary: string;
    secondary: string;
    text: string;
    background: string;
  };
  spacing: {
    small: string;
    medium: string;
    large: string;
  };
};

// テーマオブジェクト
const theme: Theme = {
  colors: {
    primary: '#3498db',
    secondary: '#2ecc71',
    text: '#2c3e50',
    background: '#ecf0f1',
  },
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px',
  },
};

ThemeProvider でラップ

typescriptexport const App = () => {
  return (
    <ThemeProvider theme={theme}>
      <div>テーマが提供されたコンテンツ</div>
    </ThemeProvider>
  );
};

ThemeProviderで囲むことで、配下のコンポーネントでthemeオブジェクトが参照できるようになります。

15. テーマ値を参照する styled component

styled コンポーネント内で、ThemeProviderから提供されたテーマ値を参照します。

styled コンポーネントの定義

typescript// themeを参照するstyledコンポーネント
const ThemedBox = styled.div`
  // theme.colors.primaryを参照
  background-color: ${(props) =>
    props.theme.colors.primary};
  color: white;
  // theme.spacing.mediumを参照
  padding: ${(props) => props.theme.spacing.medium};
  border-radius: 8px;
`;

コンポーネントでの使用

typescriptexport const ThemedComponent = () => {
  return (
    <ThemedBox>
      テーマの色と余白が適用されています
    </ThemedBox>
  );
};

props.themeでテーマオブジェクトにアクセスし、値を参照できます。

16. テーマ値を参照する css prop

css prop でも、関数形式にすることでテーマ値を参照できます。

インポート

typescript/** @jsxImportSource @emotion/react */
import { css } from '@emotion/react';
import { useTheme } from '@emotion/react';

スタイル定義(関数形式)

typescript// themeを引数に取る関数形式
const themedStyle = (theme: Theme) => css`
  background-color: ${theme.colors.secondary};
  color: white;
  padding: ${theme.spacing.large};
  border-radius: 8px;
`;

コンポーネントでの使用

typescriptexport const ThemedCssComponent = () => {
  // useThemeフックでテーマを取得
  const theme = useTheme();

  return (
    <div css={themedStyle(theme)}>
      css propでテーマを参照
    </div>
  );
};

useThemeフックでテーマを取得し、関数に渡すことで、css prop でもテーマ値が使えます。

17. ダークモード切り替え

テーマを切り替えることで、ダークモードを実装します。

ライトテーマとダークテーマの定義

typescript// ライトテーマ
const lightTheme: Theme = {
  colors: {
    primary: '#3498db',
    secondary: '#2ecc71',
    text: '#2c3e50',
    background: '#ffffff',
  },
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px',
  },
};

// ダークテーマ
const darkTheme: Theme = {
  colors: {
    primary: '#2980b9',
    secondary: '#27ae60',
    text: '#ecf0f1',
    background: '#2c3e50',
  },
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px',
  },
};

テーマ切り替え機能を持つコンポーネント

typescriptimport { useState } from 'react';

export const AppWithThemeToggle = () => {
  // ダークモードのON/OFFを管理
  const [isDark, setIsDark] = useState(false);

  // 現在のテーマを決定
  const currentTheme = isDark ? darkTheme : lightTheme;

  return (
    <ThemeProvider theme={currentTheme}>
      <Global
        styles={css`
          body {
            background-color: ${currentTheme.colors
              .background};
            color: ${currentTheme.colors.text};
          }
        `}
      />
      <div>
        <button onClick={() => setIsDark(!isDark)}>
          {isDark ? 'ライトモード' : 'ダークモード'}
          に切り替え
        </button>
        <p>現在のテーマ: {isDark ? 'ダーク' : 'ライト'}</p>
      </div>
    </ThemeProvider>
  );
};

useStateでテーマの状態を管理し、ボタンクリックで切り替えます。

18. ブレークポイントのテーマ管理

レスポンシブデザインのブレークポイントをテーマで一元管理します。

ブレークポイントを含むテーマの定義

typescript// ブレークポイントを追加したテーマ型
type ThemeWithBreakpoints = Theme & {
  breakpoints: {
    mobile: string;
    tablet: string;
    desktop: string;
  };
};

// テーマオブジェクト
const themeWithBreakpoints: ThemeWithBreakpoints = {
  colors: {
    primary: '#3498db',
    secondary: '#2ecc71',
    text: '#2c3e50',
    background: '#ffffff',
  },
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px',
  },
  breakpoints: {
    mobile: '480px',
    tablet: '768px',
    desktop: '1024px',
  },
};

ブレークポイントを参照する styled コンポーネント

typescriptconst ResponsiveContainer = styled.div`
  padding: ${(props) => props.theme.spacing.small};

  // タブレット以上
  @media (min-width: ${(props) =>
      props.theme.breakpoints.tablet}) {
    padding: ${(props) => props.theme.spacing.medium};
  }

  // デスクトップ以上
  @media (min-width: ${(props) =>
      props.theme.breakpoints.desktop}) {
    padding: ${(props) => props.theme.spacing.large};
  }
`;

コンポーネントでの使用

typescriptexport const ResponsiveApp = () => {
  return (
    <ThemeProvider theme={themeWithBreakpoints}>
      <ResponsiveContainer>
        画面幅に応じてpaddingが変わります
      </ResponsiveContainer>
    </ThemeProvider>
  );
};

ブレークポイントをテーマで管理することで、サイト全体で統一されたレスポンシブ対応が可能になります。

19. css と styled の組み合わせ

css prop とstyledコンポーネントを組み合わせることで、柔軟なスタイル管理が実現できます。

styled コンポーネントの定義

typescript// ベースとなるstyledコンポーネント
const BaseCard = styled.div`
  padding: 20px;
  border-radius: 8px;
  background-color: white;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`;

追加の css スタイル

typescript// 特定の状況で追加するスタイル
const highlightStyle = css`
  border: 2px solid #3498db;
  box-shadow: 0 4px 8px rgba(52, 152, 219, 0.3);
`;

コンポーネントでの使用

typescriptexport const CombinedCard = ({
  highlight,
}: {
  highlight?: boolean;
}) => {
  return (
    // css propで条件付きスタイルを追加
    <BaseCard css={highlight ? highlightStyle : undefined}>
      {highlight
        ? 'ハイライトされたカード'
        : '通常のカード'}
    </BaseCard>
  );
};

styled コンポーネントにcss prop を追加することで、動的なスタイル上書きが簡単にできます。

20. Theme と Global の統合パターン

最後に、ThemeProviderGlobalを統合して、アプリ全体のスタイル基盤を構築するパターンをご紹介します。

テーマ定義

typescriptconst appTheme: Theme = {
  colors: {
    primary: '#3498db',
    secondary: '#2ecc71',
    text: '#2c3e50',
    background: '#f8f9fa',
  },
  spacing: {
    small: '8px',
    medium: '16px',
    large: '24px',
  },
};

グローバルスタイル(テーマを参照)

typescript// テーマを受け取る関数形式のグローバルスタイル
const createGlobalStyles = (theme: Theme) => css`
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  body {
    font-family: -apple-system, BlinkMacSystemFont,
      'Segoe UI', Roboto, sans-serif;
    color: ${theme.colors.text};
    background-color: ${theme.colors.background};
    line-height: 1.6;
  }

  h1,
  h2,
  h3,
  h4,
  h5,
  h6 {
    color: ${theme.colors.primary};
  }

  a {
    color: ${theme.colors.primary};
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }
`;

アプリ全体に適用

typescriptexport const App = () => {
  return (
    <ThemeProvider theme={appTheme}>
      {/* テーマを参照したグローバルスタイルを適用 */}
      <Global styles={createGlobalStyles(appTheme)} />
      <div>
        <h1>アプリケーション</h1>
        <p>ThemeとGlobalが統合されたスタイル基盤です。</p>
      </div>
    </ThemeProvider>
  );
};

このパターンを使えば、テーマの切り替え時にグローバルスタイルも自動的に追従し、一貫したデザインシステムが構築できます。

以下の図は、Theme と Global を統合した全体のデータフローです。

mermaidflowchart TD
  theme_obj["テーマオブジェクト<br/>(色・余白など)"] --> provider["ThemeProvider"]
  provider -->|テーマを提供| global["Global<br/>(グローバルスタイル)"]
  provider -->|テーマを提供| components["個別コンポーネント<br/>(css / styled)"]
  global -->|ベーススタイル適用| dom["DOM全体"]
  components -->|個別スタイル適用| dom

上図のように、テーマオブジェクトをThemeProviderで提供し、Globalと各コンポーネントがそれを参照することで、統一感のあるスタイル管理が実現します。

まとめ

この記事では、Emotion の主要な 4 つの機能(cssstyledGlobalTheme)に焦点を当て、実務ですぐに使える 20 個のスニペットをご紹介しました。

css prop はシンプルで直感的なスタイル適用に、styledコンポーネントは再利用可能なコンポーネント作成に、Globalはアプリ全体の土台作りに、ThemeProviderは一貫したデザインシステム構築にそれぞれ適しています。これらを適切に使い分けることで、保守性が高く、拡張しやすいスタイリングが実現できるでしょう。

Emotion は学習コストこそありますが、一度慣れてしまえば、TypeScript との相性の良さや動的スタイリングの柔軟性が開発体験を大きく向上させてくれます。この記事のスニペットをベースに、ぜひご自身のプロジェクトで Emotion を活用してみてください。

最後までお読みいただき、ありがとうございました。

関連リンク