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