Emotion

エモーション

Emotion を分かりやすく?

Emotion は、React コンポーネント内にスタイルを記述することができる CSS-in-JS ライブラリの 1 つです。Emotion を使用すると、JavaScript の変数を使ってスタイルを定義することができ、スタイルの再利用や組み合わせが容易になります。

Emotion の特徴

Emotion の特徴は、以下の通りです。

  • JavaScript の変数を使ってスタイルを定義できる
  • スタイルの再利用や組み合わせが容易になる
  • グローバルスタイルやメディアクエリなどを簡単に実装できる
  • サーバーサイドレンダリングに対応している

@emotion/react

以下は、Emotion を使用した React コンポーネントの例です。

import { css } from '@emotion/react'

type ButtonProps = {
  text: string
  color?: string
}

const Button = ({ text, color }: ButtonProps) => {
  const styles = css`
    padding: 10px 20px;
    background-color: ${color || 'blue'};
    color: white;
    border-radius: 5px;
    &:hover {
      background-color: ${color || 'blue'}aa;
    }
  `

  return <button css={styles}>{text}</button>
}

export default Button

この例では、Button コンポーネント内でスタイルを定義しています。css関数を使用して、変数stylesにスタイルを格納しています。また、colorプロパティを指定することで、ボタンの背景色を変更できます。

@emotion/styled

こちらは、@emotion/styledを使用した React コンポーネントの例です。ネストやメディアクエリを使ってみましょう。

import Link from 'next/link'
import styled from '@emotion/styled'

const FooterStyle = styled.footer`
  background-color: black;
  .inner {
    margin: 160px auto 0;
    min-height: 200px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    place-content: center;
    max-width: calc(100% - 200px);
    @media (max-width: 768px) {
      max-width: calc(100% - 20px);
      margin: 80px auto 0;
    }
    article {
      font-size: 1.6rem;
      color: white;
      &.left {
        font-weight: bold;
        span {
          display: block;
          font-size: 1.4rem;
        }
      }
      &.right {
        text-align: right;
      }
    }
  }
`
const Footer = () => {
  return (
    <FooterStyle>
      <div className="inner">
        <article className="left">
          <Link href="/">左カラム</Link>
        </article>
        <article className="right">右カラム</article>
      </div>
    </FooterStyle>
  )
}

export default Footer

タブの実装例

Next.js と TypeScript を使って、タブをクリックすることでコンテンツを表示するコンポーネントを実装してみましょう。CSS でエラーが出る場合は、tsx の先頭に/** @jsxImportSource @emotion/react */を記述することで、JSX 内でcss関数を使用できるようになります。

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

type Tab = {
  label: string
  content: string
}

type Props = {
  tabs: Tab[]
  activeIndex?: number
  onTabClick?: (index: number) => void
  tabStyles?: {
    activeTab: any
    tabList: any
    tabContent: any
  }
}

const defaultStyles = {
  activeTab: css`
    background-color: #0070f3;
    color: #fff;
  `,
  tabList: css`
    display: flex;
    flex-wrap: wrap;
    list-style-type: none;
    margin: 0;
    padding: 0;
  `,
  tabContent: css`
    border: 1px solid #0070f3;
    padding: 8px;
  `,
}

export default function TabSwitcher({ tabs, activeIndex = 0, onTabClick, tabStyles = defaultStyles }: Props) {
  const [selectedIndex, setSelectedIndex] = useState(activeIndex)

  const handleTabClick = (index: number) => {
    setSelectedIndex(index)
    onTabClick?.(index)
  }

  return (
    <div>
      <ul css={tabStyles.tabList}>
        {tabs.map((tab, index) => (
          <li
            key={index}
            css={[
              {
                backgroundColor: '#f2f2f2',
                border: '1px solid #fff',
                cursor: 'pointer',
                padding: '8px',
                color: '#000',
              },
              index === selectedIndex && tabStyles.activeTab,
            ]}
            onClick={() => handleTabClick(index)}
          >
            {tab.label}
          </li>
        ))}
      </ul>
      <div css={tabStyles.tabContent}>{tabs[selectedIndex].content}</div>
    </div>
  )
}

まとめ

Emotion は、React コンポーネント内にスタイルを記述することができる CSS-in-JS ライブラリの 1 つです。JavaScript の変数を使ってスタイルを定義することができ、スタイルの再利用や組み合わせが容易になります。また、グローバルスタイルやメディアクエリなどを簡単に実装できるため、開発効率が向上します。