React

styled-componentsとは?メンテナンスモード後の現在地

styled-componentsとは?メンテナンスモード後の現在地

styled-componentsは、JavaScriptのタグ付きテンプレートリテラルにCSSを書き、その場でReactコンポーネントを作るライブラリです。2025年3月にメンテナが「メンテナンスモード」を宣言したため、いま検索される内容は使い方よりも「これから採用してよいのか」に移りました。ところがnpmとGitHubのリリース履歴を追うと、宣言の約10か月後に撤退理由そのものだった制約が解消されています。この記事では2026年7月時点で確認できる事実を並べたうえで、導入手順・TypeScriptの型・Material UIとの併用まで実務の要点を整理します。

まとめ

  • 最新安定版は6.4.4(2026年7月18日公開、以下の日付はUTC基準)。npmに非推奨(deprecated)フラグは付いていない。
  • 2025年3月17日、メンテナのEvan Jacobs氏がOpen Collectiveでメンテナンスモードを宣言。撤退理由の一つは「Context APIがRSCで使えず移行経路がない」ことだった。
  • その約10か月後、6.3.0(2026年1月10日)がReact Server Componentsへネイティブ対応。'use client'もレジストリも不要になり、撤退理由の一つが実装で解消された。
  • 2026年はマイナー版が3本(6.2.0・6.3.0・6.4.0)。6.4.0ではcreateTheme()が追加されIE11サポートが切られた。「機能追加をしない運用」という当初の宣言より実態は動いている。
  • それでも新規採用は避けるのが妥当。理由はRSC非対応ではなく、メンテナ本人が推奨しておらず、共同メンテナを募集中という体制側のリスクにある。
  • v6以降は型を同梱するので@types/styled-componentsは入れない。v5から上げるなら自動prop転送の廃止(transient props)とベンダープレフィックスの既定変更に注意する。

styled-componentsの仕組みと「styled」が指すもの

中心にあるのはstyledという関数群です。styled.buttonのようにHTMLタグ名を続け、直後のテンプレートリテラルにCSSを書くと、そのスタイルを持つReactコンポーネントが返ります。英単語のstyledはstyleの過去分詞で「スタイルを当てられた」の意味。スタイル済みのコンポーネントを作るという命名がそのまま機能を表しています。

import styled from 'styled-components';

const Button = styled.button`
  padding: 8px 16px;
  border-radius: 4px;
  background: #1a73e8;
  color: #fff;
`;

export default function Toolbar() {
  return <Button type="button">保存</Button>;
}

ビルド時にCSSファイルを吐き出すのではなく、レンダリング時にクラス名を生成してスタイルを注入します。この「ランタイムでCSSを組み立てる」設計が、長らくReact Server Componentsとの相性問題として語られてきました(6.3.0での解消は後述)。依存パッケージはstylis 4.3.6、csstype 3.2.3、css-to-react-native 3.2.0、@emotion/is-prop-valid 1.4.0の4つ、動作要件はNode.js 16以上、Reactは16.8以上です。

メンテナンスモード宣言と、その後に起きたこと

2025年3月17日の宣言の内容

Open Collectiveの投稿「Thank you」で、メンテナのEvan Jacobs氏は「styled-components as a project is in “maintenance mode”」と述べ、「For new projects, I would not recommend adopting styled-components or most other css-in-js solutions.」と続けました。推奨されていないのはstyled-components単体ではなくCSS-in-JSソリューション全般である点は読み違えられやすいところです。撤退理由として挙げられたのは、React本体が一部APIの位置づけを変えたこと、エコシステムの重心が移ったこと、本人が大規模な本番環境でこのライブラリを使わなくなったことでした。同じ投稿には「will continue to be available with occasional bugfixes and misc improvements」ともあり、APIの削除や公開停止は宣言されていません。

撤退理由が実装で解消された時系列

宣言本文はReactコアチームの動きについて「not available in RSC with no migration path」と書いています。Context APIがServer Componentsで使えず、移行の道筋がない、という判断です。ところがその後のリリースは逆に動きました。

版 公開日(UTC) 内容
6.2.0 2026-01-06 renderToPipeableStreamの実験的サポート
6.3.0 2026-01-10 RSCネイティブ対応、modern HTML要素とSVGフィルタ追加
6.4.0 2026-04-09 createTheme()追加、attrsのprops自動optional化、IE11打ち切り
6.4.2〜6.4.4 2026-05-19〜07-18 型検査コスト削減、Preact・Next.js Link互換の修正

6.3.0のリリースノートは「Components work in RSC without any wrapper or directive」「Works out of the box with Next.js App Router and other RSC-enabled frameworks」と明記しています。実装はtypeof React.createContext === 'undefined'でRSC環境を検出し、その場合はインラインの<style>タグを出して、React 19が自動でheadへ引き上げ重複を排除する挙動に委ねる方式です。Contextが無い環境ではContextを使わない経路へ切り替える、という形で「移行経路が無い」が解かれたことになります。副作用として、RSCではThemeProviderとStyleSheetManagerが素通り(no-op)になります。

2026年2月8日には公式ディスカッションでメンテナ本人が回答し、abandonwareではないこと、業務で使う環境が手元にないため以前のペースは出せないこと、修正とReactへの追随は続けること、現にこのライブラリを使っている共同メンテナを探していることを説明しています。日本語圏の解説記事の多くは2025年3月で情報が止まっており、「RSCに適応できずに終わった」と書かれたままです。リリース履歴はその記述を否定しています。

v7アルファで変わる点

v7は公式ドキュメントに「v7 is in alpha」と明記された開発中の版で、npm install styled-components@testで試せます。

項目 v6 v7アルファ
React要件 16.8以上 19.0以上
defaultProps 継承する 継承しない
CSS抽出 disableCSSOMInjection等 extractCSS()に一本化
ベンダープレフィックス enableVendorPrefixesで有効化 ランタイム付与を削除
プラグイン stylisPlugins prop plugins propへ改称
React Native 0.68以上(任意) 0.85以上(任意)

defaultPropsが外れるのはReact 19が関数コンポーネントからこの機能を削除したことへの追随で、公式ドキュメントはpropsの既定値は.attrs()へ、既定テーマはThemeProviderへ寄せるよう案内しています。CSS抽出の切り替えはdisableCSSOMInjectionと環境変数SC_DISABLE_SPEEDYが同時に廃止され、extractCSS()に集約されます。プラグインはstyled-components/pluginsからrscPlugin・rtlPluginをimportしてplugins propへ渡す形になり、6.4系で使っていたstylisPluginRSCは書き換えが必要です。reanimatedのアニメーションアダプタを使う場合はreact-native-reanimated 4.0以上が要ります。同じcreateGlobalStyleコンポーネントを複数回マウントしてもCSSが1回しか出力されなくなる変更も入っています。

2026年の採用判断:新規と既存の分岐

新規採用を避ける理由

新規プロジェクトでは選ばないのが妥当です。ただし理由をRSC非対応に置くのは2026年時点では誤りで、判断材料は体制側にあります。メンテナ本人が推奨しておらず、2026年の安定版はすべて同一メンテナが公開していて、その本人が共同メンテナを募集している状態です。React側に大きな変更が入ったとき、追随されるかどうかが個人の可用性に左右される依存を、新しい設計の中心に据える理由は薄いといえます。ランタイムでスタイルを組み立てるコストも、ビルド時に確定する方式と比べれば残ります。

既存プロジェクトの移行判断基準

動いているコードを書き換える作業には、それを止めてでも回収すべき利益があるかという別の判断が要ります。6.x系は現在も修正が出ており、非推奨フラグもありません。着手の妥当なきっかけは次のような行き詰まりです。

  • Reactのメジャーアップグレードで、defaultPropsなど廃止APIに依存した箇所が壊れた
  • 初期表示のスタイル生成コストが計測で問題として現れた
  • v7へ上げたいが、破壊的変更の対応工数が移行工数を上回る

逆に、これらが起きていない社内管理画面のような環境で、順番待ちの機能開発を止めてまで剥がす合理性はありません。かつて最大の移行理由だった「App Routerで使えない」は6.3.0で消えました。段階的に移すなら、新規で追加する画面から別の方式に切り替え、既存画面は触るタイミングで置き換える形が現実的です。

npm導入とNext.js・TypeScript側の設定

インストールとバージョン確認

インストールは1行です。TypeScriptプロジェクトでも追加の型パッケージは要りません。

npm install styled-components
npm view styled-components version   # 導入された安定版を確認
npm install styled-components@test   # v7アルファを試す場合

Next.js App Routerでの設定(6.3以降はレジストリ不要)

まずnext.config.jsでコンパイラを有効にします。

module.exports = {
  compiler: {
    styledComponents: true,
  },
};

ここで注意したいのが、Next.jsの公式CSS-in-JSガイドが6.3.0の変更に追随していない点です。同ガイドの更新日は2025年7月28日で、レジストリコンポーネントを作ってルートレイアウトを包む手順が今も必須のように書かれています。styled-components側の公式ドキュメントは、レジストリをレイアウトファイルへ置く必要があるのはv6.0〜6.2に限ると版を明示したうえで、その手順の参照先としてNext.jsのドキュメントを挙げています。参照している側が先に更新された、という順序の逆転が起きているわけです。6.3.0以降でレジストリは要りません。6.0〜6.2を使い続ける場合だけ、次のレジストリを用意します。

'use client';

import React, { useState } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { ServerStyleSheet, StyleSheetManager } from 'styled-components';

export default function StyledComponentsRegistry({
  children,
}: {
  children: React.ReactNode;
}) {
  const [sheet] = useState(() => new ServerStyleSheet());

  useServerInsertedHTML(() => {
    const styles = sheet.getStyleElement();
    sheet.instance.clearTag();
    return <>{styles}</>;
  });

  if (typeof window !== 'undefined') return <>{children}</>;

  return (
    <StyleSheetManager sheet={sheet.instance}>{children}</StyleSheetManager>
  );
}

サーバー側とクライアント側の役割分担そのものはReact Server Components(RSC)とは?サーバー・クライアントの違いと使い分けを実装例で解説で整理しています。

TypeScriptの型と@types/styled-components

v6以降のstyled-componentsはTypeScriptで書かれ、パッケージがdist/index.d.tsを同梱しています。公式の移行ガイドは「styled-components now provides its own types; if you installed @types/styled-components in the past, you’ll want to remove it」と削除を指示しています。DefinitelyTyped側のパッケージは5.1.x系、つまりv5向けの型のままです。TypeScriptは同梱型を先に解決するため入れた瞬間に壊れるわけではありませんが、不要な依存を増やすうえ、pathsやtypeRootsを独自に設定しているプロジェクトでは解決先が入れ替わって古い型が使われる余地が残ります。検索でこのパッケージ名に行き着いた場合は、まず自分のstyled-componentsが6.x以上かを確認してください。

テーマの型はDefaultThemeを宣言マージで拡張するとprops.themeの補完が効きます。

// styled.d.ts
import 'styled-components';

declare module 'styled-components' {
  export interface DefaultTheme {
    colors: {
      primary: string;
      danger: string;
    };
  }
}

v5から上げるときの落とし穴

v6.0.0(2023年6月28日公開)の破壊的変更は、v5のコードをそのまま動かすと静かに見た目が変わる種類のものです。リリースノートは「dropped automatic prop filtering」「dropped automatic vendor prefixing」を明記しています。前者はDOMに渡したくないpropsを$付きのtransient propsへ書き換える必要があること、後者は古いブラウザ対応が要る場合にStyleSheetManagerのenableVendorPrefixesで明示的に戻す必要があることを意味します。stylisがv4に上がった影響で、&を省いた:hoverが子孫セレクタとして解釈される点も、v5時代の記述が残っていると効かなくなる原因になります。

propsによる動的スタイリングとtransient props

propsを受け取って値を切り替えるのがこのライブラリの主な利点です。v6では渡したpropsが自動でフィルタされないため、スタイル専用のpropsには$を付けてDOMへ漏らさないようにします。付け忘れるとReactが未知の属性として警告を出し、HTMLにも不要な属性が出力されます。

import styled from 'styled-components';

const Badge = styled.span<{ $tone: 'info' | 'danger' }>`
  padding: 2px 8px;
  border-radius: 9999px;
  color: ${(props) => (props.$tone === 'danger' ? '#b3261e' : '#1a73e8')};
  background: ${(props) => (props.$tone === 'danger' ? '#fce8e6' : '#e8f0fe')};
`;

// 使用側: <Badge $tone="danger">期限切れ</Badge>

v5にあった$asと$forwardedAsはv6で廃止され、as・forwardedAsに統一されました。旧来の自動フィルタ挙動を残したい場合は、StyleSheetManagerに@emotion/is-prop-validを使ったshouldForwardPropを渡します。

RSCでのテーマ指定:createTheme()

Server Componentsではコンテキストが使えないため、ThemeProviderは素通りになります。6.4.0で追加されたcreateTheme()は、この穴を埋めるCSS変数ベースのテーマ機構です。渡したオブジェクトの末端の値がCSSカスタムプロパティの参照に置き換わり、公式ドキュメントの例ではtheme.colors.primaryがvar(--sc-colors-primary, #0070f3)に解決されます。

// theme.ts
import { createTheme } from 'styled-components';

export const theme = createTheme({
  colors: { primary: '#0070f3' },
});

// theme.colors.primary  -> var(--sc-colors-primary, #0070f3)
// theme.vars.colors.primary -> --sc-colors-primary(変数名そのもの)

ここで見落としやすいのが、戻り値のGlobalStyleをアプリのルートで1回マウントしないと:rootにCSS変数が出力されない点です。マウントを忘れてもvar()のフォールバック値が効くため画面は壊れず、テーマを切り替えても何も変わらない、という気づきにくい形で失敗します。

// app/layout.tsx など、クライアント側のルートで1回だけ
import { ThemeProvider } from 'styled-components';
import { theme } from './theme';

<ThemeProvider theme={theme}>
  <theme.GlobalStyle />
  {children}
</ThemeProvider>

// Server Component側は var() 参照を読むだけでよい
const Card = styled.div`
  color: ${theme.colors.primary};
`;

参照するのはCSS変数なので、値を差し替えてもクラス名のハッシュが変わりません。テーマ違いでハイドレーションの不一致が起きる典型的な事故を避けられるのがこの方式の実利です。切り替え役はクライアント側のThemeProviderに残り、サーバー側のコンポーネントは変数を読むだけになります。ダークモードのように値だけを差し替えたい場合は、varsから取り出した変数名をメディアクエリやクラスで上書きします。

Material UIと併用する場合の構成

Material UI(@mui/material)の既定のスタイルエンジンはemotionです。styled-componentsへ差し替えるには@mui/styled-engine-scを入れ、バンドラ側で@mui/styled-engineの解決先を置き換えます。公式ドキュメントはMaterial UI本体と同じメジャーバージョンのstyled-engine-scを使うことを求めており、2026年7月時点の@mui/material 9.2.0なら9.x系、styled-componentsは^6.0.0が対象です。

// package.json(Yarn): dependencies と resolutions の両方に書く
"dependencies": {
  "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest"
},
"resolutions": {
  "@mui/styled-engine": "npm:@mui/styled-engine-sc@latest"
}

// webpack.config.js(npm): TypeScriptならtsconfig.jsonのpathsも同様に置き換える
resolve: {
  alias: {
    '@mui/styled-engine': '@mui/styled-engine-sc'
  }
}

ただし公式ドキュメントには「As of late 2021, styled-components is not compatible with server-rendered Material UI projects.」という注記が今も残っています。@mui配下のstyled()をbabel-plugin-styled-componentsが扱えないことが理由で、サーバーレンダリングを使うMaterial UIプロジェクトではエンジンをemotionのままにするのが安全です。なお「material ui styled」で調べてMUI Systemのstyled()に行き着いた場合、それはMUI自身のユーティリティであり、styled-componentsとは別物です。

移行先の絞り込み軸:CSSを確定するタイミング

移行先を比べるときに先に見るべきなのは、機能の多寡ではなくCSSをいつ確定するかです。ここで注意したいのが、移行先の筆頭に挙がるemotionとの比較で言えば、RSCを解いたのはstyled-components側だという逆転が起きている点です。Next.jsの公式ガイドでemotionは今も「対応作業中」の分類に置かれ、App Router対応を求めるissue #2928は2022年10月に立てられて以降クローズされていません。@emotion/styledの最新公開は2025年6月26日の11.14.1です。RSC対応を理由にemotionへ移るのは、2026年時点では筋が通りません。

選択肢 CSSの確定 Server Componentで直接使えるか
styled-components 6.3以降 ランタイム 可
emotion ランタイム 不可
CSS Modules ビルド時 可
Tailwind CSS ビルド時 可
StyleX ビルド時 可

emotionの「不可」は、App Router対応issueが未クローズでNext.js公式の対応済みリストにも載っていないことによります。CSS-in-JSの記述感を残したままビルド時に静的化したいなら、Meta発の実装を扱ったMeta社の新スタイリングライブラリ「StyleX」とは?が近い選択肢です。ユーティリティクラス方式へ寄せる場合は、設定ファイルを廃してCSS側で構成する方向に変わったTailwind CSS v4の主な変更点と新機能の概要を踏まえたうえで、コンポーネント単位のバリアント管理にTailwind Variants(tv)の使い方|slots・compoundVariants・レスポンシブとTailwind CSS v4対応のような補助ライブラリを組み合わせる形になります。

よくある質問

styled-componentsは非推奨(deprecated)になったのですか?

なっていません。npmレジストリのパッケージ情報に非推奨フラグは付いておらず、2026年7月18日にも6.4.4が公開されています。2025年3月に宣言されたのは「メンテナンスモード」で、その後もマイナー版が3本出ています。

React 19やNext.js App Routerで使えますか?

使えます。6.3.0以降はServer Componentsから直接書けて'use client'もレジストリも不要です。6.0〜6.2を使っている場合のみレジストリが要ります。React 19でdefaultPropsが関数コンポーネントから外れた影響を受ける箇所は、個別の書き換えが必要です。

@types/styled-componentsはインストールすべきですか?

v6以降は不要です。本体が型定義を同梱しており、公式の移行ガイドも既存の@types/styled-componentsを削除するよう指示しています。DefinitelyTypedの型はv5系向けのままです。

RSCでThemeProviderが効かないときはどうしますか?

Server Componentsにはコンテキストが無いためThemeProviderは素通りになります。6.4.0で追加されたcreateTheme()を使い、CSSカスタムプロパティ経由でテーマ値を参照してください。

CSS Modulesとの違いは何ですか?

CSSを確定する時点が違います。CSS Modulesはビルド時にクラス名を決めてCSSファイルを出力します。styled-componentsはレンダリング時にスタイルを生成するため、propsに応じた動的なスタイルを書ける代わりに、生成処理の分だけ実行時のコストが乗ります。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

RELATED POSTS 関連記事

目次