# Next.js App Router

Use the controlled banner inside a client boundary and import its stylesheet once.

Source: https://docs.peax.co/consent/frameworks/nextjs



## Install and create the wrapper [#install-and-create-the-wrapper]

Follow the [Quickstart](/consent/quickstart). The `CookieBanner` file must start with `'use client'`.

Import the theme stylesheet in your root layout:

```tsx
import '@peax/consent-banner-theme/styles.css'
import { ConsentIntegration } from './consent-integration'
import type { ReactNode } from 'react'

export default function RootLayout({ children }: { children: ReactNode }) {
  return <html lang="en"><body>{children}<ConsentIntegration /></body></html>
}
```

## Keep callbacks in the client boundary [#keep-callbacks-in-the-client-boundary]

```tsx
'use client'

import { useState } from 'react'

import { CookieBanner } from './cookie-banner'
import type { Preferences } from './cookie-banner'

export function ConsentIntegration() {
	const [choices, setChoices] = useState<Preferences | null>(null)
	return (
		<>
			<p role="status">{choices ? 'Demo choices recorded in memory.' : 'No demo choice recorded.'}</p>
			<CookieBanner initialPreferences={null} onCommit={setChoices} />
		</>
	)
}

```

Copy this integration alongside the wrapper, adjusting its relative import as needed. This example keeps choices in memory; connect your actual storage and optional-service controls before shipping.

When reading saved consent on the server, pass serializable data into the client wrapper and keep first-render values consistent. Keep functions such as `onCommit` inside the client boundary. With client-only storage, wait until restoration completes before initializing the wrapper.

## Verify your integration [#verify-your-integration]

Check a fresh visit, a returning visit, Accept, Reject, Apply and reopening choices. Confirm that optional scripts remain blocked before consent and respond to revocation. See [integration responsibilities](/consent/concepts/integration).
