CSS-in-JS
警告: 実行時に JavaScript を必要とする CSS-in-JS ライブラリは現在、Server Components でサポートされていません。CSS-in-JS を使って新しい React の機能 (Server Components や Streaming など) を利用するには、ライブラリの開発者が React の最新バージョン、特に 並行レンダリング をサポートする必要があります。
我々は、React Server Components とストリーミングアーキテクチャのサポートを含む CSS と JavaScript アセットを処理するための上流 API を React チームと協力して開発しています。
以下のライブラリが app
ディレクトリ内の Client Components でサポートされています(アルファベット順):
ant-design
chakra-ui
@fluentui/react-components
kuma-ui
@mui/material
@mui/joy
pandacss
styled-jsx
styled-components
stylex
tamagui
tss-react
vanilla-extract
以下は現在サポートに取り組んでいます:
Good to know: さまざまな CSS-in-JS ライブラリを試しており、React 18 の機能や
app
ディレクトリをサポートするライブラリのサンプルを増やしていく予定です。
Server Components のスタイルを定義したい場合は、CSS モジュール など、CSS ファイルを出力する他のソリューション、PostCSS や Tailwind CSS などをお勧めします。
app
での CSS-in-JS の設定
CSS-in-JS の設定は、以下の 3 つの手順からなるオプトインのプロセスです。
- 描画中にすべての CSS ルールを収集する スタイルレジストリ。
- それらを使用する可能性があるコンテンツの前にルールを挿入するための新しい
useServerInsertedHTML
フック。 - 初期のサーバーサイドレンダリング時にアプリをスタイルレジストリでラップする Client Component。
styled-jsx
Client Components で styled-jsx
を使用するには、v5.1.0
を使用する必要があります。まず、新しいレジストリを作成します:
- TypeScript
- JavaScript
'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>
}
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { StyleRegistry, createStyleRegistry } from 'styled-jsx'
export default function StyledJsxRegistry({ children }) {
// 初期状態が遅延された状態でスタイルシートを一度だけ作成するようにする
// 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 レイアウト をレジストリでラップします:
- TypeScript
- JavaScript
import StyledJsxRegistry from './registry'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
)
}
import StyledJsxRegistry from './registry'
export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledJsxRegistry>{children}</StyledJsxRegistry>
</body>
</html>
)
}
Styled Components
以下は styled-components@6
以上を設定する方法の例です:
まず、next.config.js
で styled-components を有効にします。
module.exports = {
compiler: {
styledComponents: true,
},
}
次に、styled-components
の API を使用して、描画中に生成されるすべての CSS スタイルルールを収集するためのグローバルなレジストリコンポーネントを作成し、それらのルールを返す関数を作成します。そして、useServerInsertedHTML
フックを使って、レジストリに収集されたスタイルを root レイアウトの <head>
HTML タグに挿入します。
- TypeScript
- JavaScript
'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>
)
}
'use client'
import React, { useState } from 'react'
import { useServerInsertedHTML } from 'next/navigation'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
export default function StyledComponentsRegistry({ children }) {
// 初期状態が遅延された状態でスタイルシートを一度だけ作成するようにする
// 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
をスタイルレジストリコンポーネントでラップします:
- TypeScript
- JavaScript
import StyledComponentsRegistry from './lib/registry'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}
import StyledComponentsRegistry from './lib/registry'
export default function RootLayout({ children }) {
return (
<html>
<body>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</body>
</html>
)
}
Good to know:
- サーバーレンダリング中、スタイルはグローバルなレジストリに抽出され、HTML の
<head>
にフラッシュされます。これは、スタイルルールがそれらを使用する可能性のあるコンテンツの前に配置されることを保証します。将来的には、スタイルの挿入場所を決定するために、新しい React の機能を使用することがあります。- ストリーミング中、各チャンクからのスタイルは収集され、既存のスタイルに追加されます。クライアント側のハイドレーションが完了すると
styled-components
が通常通り動作し、さらなる動的なスタイルを挿入します。- スタイルレジストリをトップレベルの tree で使用する理由は、この方法が CSS ルールを抽出するのに効率的だからです。これにより、後続のサーバーレンダリングでスタイルが再生成されるのを避け、Server Component のペイロードでそれらが送信されるのを防ぎます。
- styled-components のコンパイルの個々のプロパティを設定する必要がある高度なユースケースに対しては、Next.js の styled-components API リファレンスを参照して詳細を学んでください。