---
title: "CookieConsentBanner"
description: "The cookie consent banner component, how SysthemaProvider mounts it, and its config, theme, layout and reopen link."
requested_language: ar
language: en
translation_notice: "This page isn't translated yet"
url: https://docs.systhema.app/ar/next/components/cookie-consent-banner
version: unreleased (main)
docs_index: https://docs.systhema.app/ar/next/llms.txt
---
> This page isn't translated yet. Showing English.


`CookieConsentBanner` shows the cookie consent banner and preferences modal, built on [vanilla-cookieconsent](https://cookieconsent.orestbida.com/) and themed by the `cookieConsent` tokens. It renders no DOM of its own: it starts the consent library on the client, which adds its markup to `<body>`. You rarely render it yourself, because [`SysthemaProvider`](https://docs.systhema.app/ar/next/components/provider.md#with-cookie-consent) mounts it whenever it receives an enabled config.

```tsx preview iframe height=480 title="Consent banner"
import { CookieConsentBanner, Heading, Paragraph } from '@systhemaui/next'
import type { SysthemaCookieConsentConfig } from '@systhemaui/core'

const config: SysthemaCookieConsentConfig = {
  enabled: true,
  cookie: { name: 'docs_demo_consent' },
  hideFromBots: false,
  categories: {
    necessary: { readOnly: true, enabledByDefault: true },
    analytics: { enabledByDefault: false },
  },
  policyLinks: [{ label: 'Privacy policy', url: '#privacy' }],
  translations: {
    en: {
      consentModal: {
        title: 'We use cookies',
        description: 'Some keep the site working, others help us understand how it is used.',
        acceptAllBtn: 'Accept all',
        acceptNecessaryBtn: 'Necessary only',
        showPreferencesBtn: 'Choose',
      },
      preferencesModal: {
        title: 'Cookie preferences',
        acceptAllBtn: 'Accept all',
        acceptNecessaryBtn: 'Necessary only',
        savePreferencesBtn: 'Save choices',
        sections: {
          necessary: { title: 'Necessary', description: 'Required for the site to work.' },
          analytics: { title: 'Analytics', description: 'Anonymous usage statistics.' },
        },
      },
    },
  },
}

export default function Demo() {
  return (
    <>
      <Heading.h3>Northwind</Heading.h3>
      <Paragraph>
        Made your choice already?{' '}
        <a className="link" href="#cookie-settings">
          Cookie settings
        </a>{' '}
        opens the preferences again.
      </Paragraph>
      <CookieConsentBanner config={config} />
    </>
  )
}
```

## Import

```tsx
import { CookieConsentBanner } from '@systhemaui/next'
```

In a React app without Next.js, import it from `@systhemaui/react`.

## Usage

### Through the provider

Pass the resolved config to `SysthemaProvider`. `getSysthemaCookieConsentConfig()` reads `cookieConsent` from `systhema.config.ts`, merges the cookies found by the [scanner](https://docs.systhema.app/ar/next/guides/cookie-consent/scanner.md), and returns `null` while `enabled` is not `true`, in which case nothing mounts:

```tsx title="app/layout.tsx"
import type { ReactNode } from 'react'
import { SysthemaProvider, getSysthemaCookieConsentConfig } from '@systhemaui/next'

export default function RootLayout({ children }: { children: ReactNode }) {
  const cookieConsent = getSysthemaCookieConsentConfig()

  return (
    <html lang="en">
      <body>
        <SysthemaProvider cookieConsent={cookieConsent}>{children}</SysthemaProvider>
      </body>
    </html>
  )
}
```

In a Payload project, `RootLayout` from `@systhemaui/payload` resolves the config from the General Settings global on the server and passes it on, so editors control the texts, links and theme. See [Cookie consent](https://docs.systhema.app/ar/next/guides/cookie-consent.md#project-setup).

### On its own

Render the component directly when you don't use the provider. Mount it once, in a layout that persists across pages:

```tsx
import { CookieConsentBanner, getSysthemaCookieConsentConfig } from '@systhemaui/next'

export function Consent() {
  const config = getSysthemaCookieConsentConfig()
  return config ? <CookieConsentBanner config={config} /> : null
}
```

## Examples

### Config

The `config` prop is a `SysthemaCookieConsentConfig`. The keys that shape the banner:

| Key               | What it does                                                                                                             |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `enabled`         | Must be `true`, or the component does nothing                                                                            |
| `categories`      | Per category (`necessary`, `functional`, `analytics`, `performance`, `advertisement`): `enabledByDefault` and `readOnly` |
| `translations`    | The texts per language: `consentModal`, `preferencesModal` and its `sections`                                            |
| `defaultLanguage` | The language to start with (default `en`); the `<html lang>` wins when a translation exists for it                       |
| `policyLinks`     | Links composed into the consent modal footer                                                                             |
| `theme`           | A color-system mode for the banner alone                                                                                 |
| `guiOptions`      | vanilla-cookieconsent's layout and position options, passed through                                                      |
| `reopenSelector`  | Elements that reopen the preferences (default `a[href="#cookie-settings"]`); `false` turns the listener off              |

The full shape, including `cookies`, `cookie` and the scanner options, is on [Configuration](https://docs.systhema.app/ar/next/guides/cookie-consent/configuration.md).

### Theme and layout

`theme` re-themes the banner independently of the page: the component sets `data-theme` on the banner root (`#cc-main`), and the `cookieConsent` tokens follow. `'inherit'`, or no value, uses the page's theme. `guiOptions` picks vanilla-cookieconsent's layouts; the default is a box in the bottom right corner with a box preferences modal.

```tsx preview iframe height=480 title="Dark bar layout"
import { CookieConsentBanner, Heading, Paragraph } from '@systhemaui/next'
import type { SysthemaCookieConsentConfig } from '@systhemaui/core'

const config: SysthemaCookieConsentConfig = {
  enabled: true,
  cookie: { name: 'docs_demo_consent_bar' },
  hideFromBots: false,
  theme: 'dark',
  guiOptions: {
    consentModal: { layout: 'bar inline', position: 'bottom' },
    preferencesModal: { layout: 'box' },
  },
  categories: {
    necessary: { readOnly: true, enabledByDefault: true },
    analytics: { enabledByDefault: false },
  },
  policyLinks: [{ label: 'Privacy policy', url: '#privacy' }],
  translations: {
    en: {
      consentModal: {
        title: 'We use cookies',
        description: 'Some keep the site working, others help us understand how it is used.',
        acceptAllBtn: 'Accept all',
        acceptNecessaryBtn: 'Necessary only',
        showPreferencesBtn: 'Choose',
      },
      preferencesModal: {
        title: 'Cookie preferences',
        acceptAllBtn: 'Accept all',
        acceptNecessaryBtn: 'Necessary only',
        savePreferencesBtn: 'Save choices',
        sections: {
          necessary: { title: 'Necessary', description: 'Required for the site to work.' },
          analytics: { title: 'Analytics', description: 'Anonymous usage statistics.' },
        },
      },
    },
  },
}

export default function Demo() {
  return (
    <>
      <Heading.h3>A light page with a dark banner</Heading.h3>
      <Paragraph>
        Made your choice already?{' '}
        <a className="link" href="#cookie-settings">
          Cookie settings
        </a>{' '}
        opens the preferences again.
      </Paragraph>
      <CookieConsentBanner config={config} />
    </>
  )
}
```

### Reopen link

The banner closes for good once the visitor chooses. Put a link to `#cookie-settings` in your footer so they can change their mind; a click on it opens the preferences modal. The demos above have one.

```tsx
;<a href="#cookie-settings">Cookie settings</a>
```

## How it works

- vanilla-cookieconsent and its stylesheet are imported on the client only, inside an effect, so server rendering and Node tooling never load them. The `cc--systhema` class lands on `<html>` after the stylesheet has loaded, and the core CSS keeps the banner hidden until then, so it never flashes unstyled.
- The library is a page-wide singleton, so the component starts it once per page load. A second `CookieConsentBanner`, a remount in React Strict Mode or a hot reload attaches only the reopen listener again; in development, a console warning reports another initializer that ran first.
- The banner runs in opt-in mode and manages `<script type="text/plain" data-category="…">` tags, which run once their category is accepted. See [Gating third-party scripts](https://docs.systhema.app/ar/next/guides/cookie-consent.md#gating-third-party-scripts).
- Changing `config.theme` re-themes a mounted banner on the next render; other config changes take effect on the next page load.

### Browser automation

vanilla-cookieconsent hides the banner from bots by default (`hideFromBots: true`). Its check matches every automated browser through `navigator.webdriver`, so Playwright, Puppeteer and agent-driven QA see no banner and no error. The component logs `[systhema] Cookie consent banner suppressed: …` to the console when that happens. Set `hideFromBots: false` for an end-to-end run; it is only passed on when you set it, so the library's default stays in force everywhere else. The demos on this page set it so they render in screenshot tools too.

## Props

<!-- generated:props @systhemaui/react CookieConsentBannerProps -->

| Prop                | Type                          | Default | Description |
| ------------------- | ----------------------------- | ------- | ----------- |
| `config` (required) | `SysthemaCookieConsentConfig` | -       |             |

<!-- /generated -->

## HTML and CSS

HTML projects get the same banner from the [vanilla JS bundle](https://docs.systhema.app/ar/next/styling/vanilla-js.md): set the config on `window.__SYSTHEMA_COOKIE_CONSENT__` before the bundle loads.

```html
<script>
  window.__SYSTHEMA_COOKIE_CONSENT__ = {
    enabled: true,
    policyLinks: [{ label: 'Privacy policy', url: '/privacy-policy' }],
  }
</script>
<script src="node_modules/@systhemaui/core/dist/js/bundle.global.js" defer></script>

<footer>
  <a href="#cookie-settings">Cookie settings</a>
</footer>
```

The banner is styled by the `cookieConsent` block of the core CSS, scoped to `.cc--systhema`, from the `cookieConsent` tokens in [colors](https://docs.systhema.app/ar/next/reference/tokens/colors.md#cookieconsent) and [spacing](https://docs.systhema.app/ar/next/reference/tokens/spacing.md#cookieconsent). See [Theming the banner](https://docs.systhema.app/ar/next/guides/cookie-consent/theming.md).

## Next.js

`@systhemaui/next` re-exports `CookieConsentBanner` from `@systhemaui/react` and `getSysthemaCookieConsentConfig` from the client-safe `@systhemaui/core/client` entry, so a Next.js app imports both from `@systhemaui/next` without pulling the token dataset into a client bundle. The component is a client component; render it from a Server Component layout as it is.

## Accessibility

- vanilla-cookieconsent renders the banner and the preferences modal as dialogs with real buttons, operable from the keyboard.
- Policy links that open a new tab get `rel="noopener noreferrer"` and an "(opens in new tab)" suffix in their accessible name, translatable with `opensInNewTabLabel`.
- The close button of the preferences modal gets a translated label (`closeIconLabel`), with a built-in default per language.
- The banner's colors come from your tokens; check their contrast in both themes.

## Related

- [Cookie consent](https://docs.systhema.app/ar/next/guides/cookie-consent.md)
- [Configuration](https://docs.systhema.app/ar/next/guides/cookie-consent/configuration.md)
- [Theming the banner](https://docs.systhema.app/ar/next/guides/cookie-consent/theming.md)
- [SysthemaProvider](https://docs.systhema.app/ar/next/components/provider.md)
