メインコンテンツまでスキップ

CSS-in-JS

警告: CSS-in-JSをServer ComponentsやStreamingのような新しいReact機能と一緒に使用するには、ライブラリの作者が最新のReactバージョンをサポートする必要があります。これにはconcurrent renderingも含まれます。

以下のライブラリは、appディレクトリ内のClient Componentsでサポートされています(アルファベット順):

以下のライブラリは現在サポートに取り組んでいます:

Good to know: 異なるCSS-in-JSライブラリをテストしており、React 18の機能やappディレクトリをサポートするライブラリの例を追加していく予定です。

Server Componentsをスタイル付けしたい場合は、CSS Modulesや、PostCSSやTailwind CSSのようにCSSファイルを出力する他のソリューションを使用することをお勧めします。

appでのCSS-in-JSの設定

CSS-in-JSの設定は、以下の3ステップのオプトインプロセスを含みます:

  1. レンダリング中にすべてのCSSルールを収集するためのスタイルレジストリ
  2. それらを使用する可能性のあるコンテンツの前にルールを挿入するための新しいuseServerInsertedHTMLフック。
  3. 初期のサーバーサイドレンダリング中にアプリをスタイルレジストリでラップするClient Component。

styled-jsx

Client Componentsでstyled-jsxを使用するには、v5.1.0を使用する必要があります。まず、新しいレジストリを作成します:

app/registry.tsx
'use client'

import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'

export default function StyledJsxRegistry({
children,
}: {
children: React.ReactNode
}) {
// 遅延初期状態でスタイルシートを一度だけ作成する
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [jsxStyleRegistry] = useState(() => createStyleRegistry())

useServerInsertedHTML(() => {
const styles = jsxStyleRegistry.styles()
jsxStyleRegistry.flush()
return <>{styles}</>
})

return <StyleRegistry registry={jsxStyleRegistry}>{children}</StyleRegistry>
}

次に、root レイアウトをレジストリでラップします:

app/layout.tsx
import StyledJsxRegistry from './registry'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
)
}

こちらで例を確認できます

Styled Components

以下は、styled-components@6以降を設定する方法の例です:

まず、next.config.jsでstyled-componentsを有効にします。

next.config.js
module.exports = {
compiler: {
styledComponents: true,
},
}

次に、styled-components APIを使用して、レンダリング中に生成されたすべてのCSSスタイルルールを収集するグローバルレジストリコンポーネントを作成し、それらのルールを返す関数を作成します。次に、useServerInsertedHTMLフックを使用して、レジストリに収集されたスタイルをroot レイアウトの<head> HTMLタグに挿入します。

lib/registry.tsx
'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
}) {
// 遅延初期状態でスタイルシートを一度だけ作成する
// x-ref: https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
const [styledComponentsStyleSheet] = useState(() => new ServerStyleSheet())

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

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

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

root レイアウトのchildrenをスタイルレジストリコンポーネントでラップします:

app/layout.tsx
import StyledComponentsRegistry from './lib/registry'

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}

こちらで例を確認できます

Good to know:

  • サーバーレンダリング中、スタイルはグローバルレジストリに抽出され、HTMLの<head>にフラッシュされます。これにより、スタイルルールがそれらを使用する可能性のあるコンテンツの前に配置されることが保証されます。将来的には、スタイルを挿入する場所を決定するために、今後のReact機能を使用するかもしれません。
  • ストリーミング中、各チャンクからのスタイルは収集され、既存のスタイルに追加されます。クライアントサイドのハイドレーションが完了した後、styled-componentsは通常どおり動作し、さらに動的なスタイルを挿入します。
  • スタイルレジストリのためにツリーの最上位でClient Componentを使用するのは、CSSルールを抽出するのに効率的だからです。これにより、後続のサーバーレンダリングでスタイルが再生成されるのを防ぎ、Server Componentのペイロードに送信されるのを防ぎます。
  • styled-componentsのコンパイルの個々のプロパティを設定する必要がある高度なユースケースについては、Next.js styled-components APIリファレンスを読んで詳細を学ぶことができます。