# Waku

Integrate the banner through a client component in a Waku application.

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



## Add the controlled wrapper [#add-the-controlled-wrapper]

Install the packages from the [Quickstart](/consent/quickstart) and copy its `CookieBanner` into a client component. Keep the `'use client'` directive: state and event callbacks must run in the browser.

Import `@peax/consent-banner-theme/styles.css` once from a rendered layout or client component, such as `consent-integration.tsx`. The React package does not load it automatically. Importing global CSS only from a configuration-based `src/router.tsx` does not attach it to rendered pages; keep the import in a component used by those pages.

## Mount from a client integration [#mount-from-a-client-integration]

A server component cannot pass an ordinary callback to a client component. Put the application-owned `onCommit` handler in a client integration component and render that integration from your page or layout.

```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} />
		</>
	)
}

```

This minimal example holds choices in memory. Replace that boundary with your actual persistence and enforcement adapter before shipping.

## Static rendering and hydration [#static-rendering-and-hydration]

The package is safe to import on the server. Use the same locale, initial choices and visibility for the server render and first client render. Do not access `window` or storage during module initialization.

For browser-only saved choices, render a stable loading state on the server and first client render; resolve storage after mounting, then mount the wrapper. The initial sample always starts with a new visitor and is intended to verify rendering, not durable storage.

Mount the banner outside transformed or clipped ancestors that create restrictive stacking contexts. The docs demonstration isolates it in an iframe for this reason.
