Next.js と TypeScript で、Emotion Styled Components を学ぶ

TwitterFacebookHatena

TL;DR

この記事では、Next.js と TypeScript を用いて、Emotion Styled Components の効果的な実装方法について解説します。具体的なソースコードを通じて、最新の React 18 に対応した実装スタイルを深掘りします。

開発環境 バージョン
Next.js 13.4.3
TypeScript 5.0.4
Emotion 11.11.0
React 18.2.0

Emotion Styled Components とは?

Emotion Styled Components は、React で使われる CSS-in-JS の一つで、JavaScript の中に CSS を書くことができます。つまり、コンポーネントにスタイルを直接適用することができ、それぞれのコンポーネントが独立したスタイルを持つことができます。この技術は、大規模なアプリケーションにおいて特に有効で、コンポーネントの再利用性を高め、コードの可読性とメンテナンス性を向上させます。

以下に基本的な Emotion Styled Components の使用例をお見せします。

import styled from '@emotion/styled'

// Button コンポーネントの作成
const Button = styled.button`
  color: white;
  background-color: hotpink;
  font-size: 24px;
  padding: 10px;
  border-radius: 4px;
  cursor: pointer;
  &:hover {
    background-color: darkorange;
  }
`

// Container コンポーネントの作成
const Container = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
`

// App コンポーネントで Button と Container を使用
export default function App() {
  return (
    <Container>
      <Button>Click me!</Button>
    </Container>
  )
}

このコードは、ホットピンクの背景色と白い文字色を持つボタンを作成しています。さらに、ボタンはマウスオーバーすると色がダークオレンジに変わります。また、Container コンポーネントは要素を中央に配置するためのフレックスボックスコンテナとして機能します。このコンポーネントはビューポートの高さ全体を占め、内部の要素を中央に配置します。

次に公式サイトのコードを解説します。

import styled from '@emotion/styled'

const Basic = ({ className }) => <div className={className}>Some text</div>

const Fancy = styled(Basic)`
  color: hotpink;
`

render(<Fancy />)

このコードは、ウェブページ上のテキストに特別な色とスタイルを付けるものです。具体的には、普通のテキスト("Some text")をホットピンク色にするという役割を果たしています。

まず最初に、Basicという名前の部品(コンポーネント)を作ります。この部品はただの箱(<div>)で、中に"Some text"という文字が入っています。classNameという特別な情報をこの箱につけることができます。このclassNameは、箱にどんなスタイル(見た目)をつけるかを決める情報です。

次に、Fancyという新しい部品を作ります。この部品はBasic部品を基にして作られ、更にスタイルを追加しています。具体的には、color: hotpink;というスタイルを追加して、テキストの色をホットピンクに変更しています。

最後に、<Fancy />を表示することで、ホットピンク色の"Some text"というテキストがウェブページ上に現れます。

Next.js で、Emotion Styled Components を実装

Emotion Styled Components を Next.js プロジェクトに導入してみましょう。

まず、必要なパッケージをインストールします。

npm install @emotion/react @emotion/styled

次に、Emotion を利用した Button コンポーネントを作成します。

components/Button.tsx

/** @jsxImportSource @emotion/react */
import styled from '@emotion/styled'

type ButtonProps = {
  label: string
  primary?: boolean
}

const StyledButton = styled.button<ButtonProps>`
  padding: 10px 20px;
  font-size: 16px;
  color: ${(props) => (props.primary ? 'white' : 'black')};
  background-color: ${(props) => (props.primary ? 'hotpink' : 'white')};
  border: none;
  border-radius: 4px;
  cursor: pointer;
`

const Button = ({ label, primary }: ButtonProps) => {
  return <StyledButton primary={primary}>{label}</StyledButton>
}

export default Button

この Button コンポーネントは、プロパティprimaryに基づいて異なるスタイルを適用します。primaryが true の場合、ボタンはホットピンクの背景色と白い文字色を持ちます。

この Button コンポーネントを利用するために、以下のようにページから呼び出します。

pages/index.tsx

import Button from '../components/Button'

export default function Home() {
  return (
    <div>
      <Button label="Primary Button" primary />
      <Button label="Secondary Button" />
    </div>
  )
}

テーマ機能で、レイアウトを一元管理する

Emotion Styled Components をさらに活用するために、テーマ機能を利用してみましょう。これにより、全体の色調やフォントなどを一元的に管理することができます。

まず、テーマを定義します。

theme.ts

const theme = {
  colors: {
    primary: 'hotpink',
    secondary: 'black',
    background: 'white',
  },
  fonts: {
    base: 'Arial, sans-serif',
  },
}

export default theme

そして、Emotion のThemeProviderを使用して、これをアプリ全体で利用できるようにします。

pages/_app.tsx

import { ThemeProvider } from '@emotion/react'
import theme from '../theme'
import type { AppProps } from 'next/app'

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ThemeProvider theme={theme}>
      <Component {...pageProps} />
    </ThemeProvider>
  )
}

export default MyApp

これにより、スタイル定義の中からテーマを参照することが可能になります。

components/Button.tsx

import styled from '@emotion/styled'

type ButtonProps = {
  label: string
  primary?: boolean
}

const StyledButton = styled.button<ButtonProps>`
  padding: 10px 20px;
  font-size: 16px;
  color: ${(props) => (props.primary ? props.theme.colors.background : props.theme.colors.secondary)};
  background-color: ${(props) => (props.primary ? props.theme.colors.primary : props.theme.colors.background)};
  border: none;
  border-radius: 4px;
  cursor: pointer;
`

const Button = ({ label, primary }: ButtonProps) => {
  return <StyledButton primary={primary}>{label}</StyledButton>
}

export default Button

これにより、一貫したデザインを簡単に実装することができます。また、将来的なデザインの変更も容易になります。

Next.js と TypeScript で、Emotion Styled Components を学ぶ