はじめに
Reactでコンポーネントを作るとき、CSSファイルとJSXを行ったり来たりするのに疲れたことはないでしょうか。クラス名の命名に頭を悩ませたり、CSSファイルを消し忘れて不要なスタイルが残り続けたり、どのクラスがどのコンポーネントで使われているか分からなくなったり。CSSとコンポーネントが別ファイルに分かれている以上、この手の悩みはついて回ります。
Styled-Componentsは、この問題に「CSSをJavaScriptの中に書いてしまう」というアプローチで応えるライブラリです。タグ付きテンプレートリテラルを使ってコンポーネント単位でスタイルを定義し、クラス名の衝突やファイルの散在から解放してくれます。
とはいえ、読むより触った方が早いと思います。実際にボタンの見た目がPropsに応じて変わる様子を確認できるので、先に挙動を見たい方はこちらからどうぞ。
Styled-Componentsとは
Styled-Componentsは、CSS-in-JSと呼ばれる手法を代表するライブラリの1つで、Reactコンポーネントに直接CSSを結びつけて記述できるようにします。styled.divのようなタグ付きテンプレートリテラルでスタイル付きコンポーネントを作成すると、内部でユニークなクラス名が自動生成され、他のコンポーネントとスタイルが衝突する心配がありません。
主な特徴
- コンポーネント単位のスコープ化 - 生成されるクラス名は自動でユニーク化されるため、CSSの詳細度やグローバル汚染を気にする必要がありません
- Propsに応じた動的スタイリング - テンプレートリテラルの中でJavaScriptの関数を使い、Propsの値に応じてCSSを切り替えられます
- テーマ機能 -
ThemeProviderでアプリ全体にテーマを配信し、色やフォントサイズなどを一元管理できます - 未使用CSSの自動除去 - 実際にレンダリングされたコンポーネントのスタイルだけがブラウザに送られます
インストール
npm、yarn、pnpmのいずれかでインストールできます。
npm install styled-components
yarn add styled-components
pnpm add styled-components
TypeScriptを使っている場合、v6以降は型定義が同梱されているため追加のパッケージは不要です。
Styled-Componentsのサンプルを動かす
以下はstyled-componentsのもっとも基本的な使い方です。styled.buttonでスタイル付きのボタンコンポーネントを作り、primaryというPropsの値によって背景色を切り替えています。ボタンをクリックするとprimaryのオン・オフが切り替わり、見た目がその場でリアクティブに変化します。
const Button = styled.button`
padding: 10px 20px;
border-radius: 6px;
border: none;
background: ${(props) => (props.primary ? '#6772e5' : '#e0e0e0')};
color: ${(props) => (props.primary ? '#fff' : '#333')};
cursor: pointer;
transition: background 0.2s;
`
function App() {
const [primary, setPrimary] = useState(true)
return (
<Button primary={primary} onClick={() => setPrimary(!primary)}>
{primary ? 'Primaryボタン' : 'Secondaryボタン'}
</Button>
)
}
実際に動かせるものが下です。ボタンをクリックするとprimary propsが切り替わり、styled.button内の三項演算子で分岐した背景色・文字色がリアルタイムに反映されます。
このサンプルのbackgroundやcolorの三項演算子部分を書き換えると、primaryがfalseのときの見た目を自由に変えられます。$primaryのように先頭に$を付けたPropsは「トランジエントProps」と呼ばれ、DOM要素にはそのまま渡らずスタイル計算にだけ使われる仕組みになっています。
基本的な使い方
タグ付きテンプレートリテラルの中に通常のCSSをそのまま書けるのが、Styled-Componentsの基本です。styled.要素名の形でHTMLタグに対応するコンポーネントを作成します。
import styled from 'styled-components'
const Card = styled.div`
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 20px;
`
const Title = styled.h2`
font-size: 20px;
color: #333;
margin-bottom: 8px;
`
function ProfileCard() {
return (
<Card>
<Title>山田太郎</Title>
<p>フロントエンドエンジニア</p>
</Card>
)
}
CardやTitleは普通のReactコンポーネントとして扱えるため、他のコンポーネントにclassNameを渡したり、条件分岐でスタイルを変えたりする既存の知識がそのまま活用できます。
実践的なユースケース
ThemeProviderによるテーマ管理
アプリ全体で色やフォントを統一したい場合、ThemeProviderを使うと配下のすべてのStyled-Componentsからprops.theme経由でテーマの値を参照できます。ダークモードの切り替えなど、アプリ全体のトーンを一括で変えたいケースに向いています。
lightThemeとdarkThemeのオブジェクトにキーを追加すれば、props.theme.新しいキーという形でどのコンポーネントからでも同じ値を参照できます。テーマの型をTypeScriptで定義しておくと、存在しないキーの参照をコンパイル時に検出できるようになります。
createGlobalStyleによるグローバルスタイル
Styled-Componentsは基本的にコンポーネント単位でスコープ化されますが、bodyのリセットCSSやフォント指定など、アプリ全体に適用したいスタイルもあります。そうした用途にはcreateGlobalStyleを使います。
createGlobalStyleもタグ付きテンプレートリテラルなので、通常のStyled-Componentsと同様にPropsを受け取って値を差し込めます。ボタンを押すとbody直下のfont-familyがGeorgiaとsans-serifで切り替わる様子が確認できます。
既存コンポーネントの拡張
styled(Component)という書き方を使うと、すでにあるStyled-Componentsのスタイルを引き継ぎつつ、差分だけを追加した新しいコンポーネントを作れます。ボタンのバリエーションを増やしたいときに便利なパターンです。
コンソールを開いた状態で各ボタンを押すと、onClickがそれぞれ独立して発火することが分かります。DangerButtonはButtonのpaddingやfont-sizeを引き継ぎながら、border-colorとcolorだけを上書きしています。共通の見た目を持つボタンのバリエーションを増やすたびに全プロパティを書き直す必要がなくなります。
まとめ
Styled-ComponentsはCSSファイルとコンポーネントの対応関係を気にする必要をなくし、Propsに応じた動的なスタイリングやテーマ管理を、Reactの書き方にそのまま乗せて実現できるライブラリです。クラス名の衝突を心配しなくて良い点、ThemeProviderでアプリ全体のトーンを一元管理できる点は、コンポーネント数が増えてきたプロジェクトほど効果を感じやすいはずです。
まずは今回のサンプルを手元で書き換えてみて、Propsによってスタイルがどう変化するかを体感してみてください。慣れてきたら、既存のCSSファイルの一部をStyled-Componentsに置き換えるところから試してみるのがおすすめです。