Consent configuration
Configure categories, translations, policy links and server resolution for the cookie banner.
On this page
Configure the banner through cookieConsent in systhema.config.ts. In Payload projects, the exposed values seed General Settings; editors then control those fields. In Next.js projects without Payload, pass the resolved config to the provider.
systhema.configLink to this section
Merge this block into your existing configuration:
import type { SysthemaConfig } from '@systhemaui/core'
import manifest from './src/tokens/manifest.json'
const config: SysthemaConfig = {
manifest,
packages: { react: true },
cookieConsent: {
enabled: true,
defaultLanguage: 'en',
policyLinks: [
{ label: 'Privacy policy', url: '/privacy-policy' },
{ label: 'Cookie policy', url: '/cookie-policy' },
],
scanner: {
include: ['src/**/*.{ts,tsx,js,jsx}'],
exclude: ['**/node_modules/**', '**/dist/**'],
},
translations: {
en: {
consentModal: { title: 'We use cookies' },
preferencesModal: { title: 'Cookie preferences' },
},
},
},
}
export default configRetain your other package settings, custom tokens and design inputs. enabled defaults to false. You can gate it with process.env.NEXT_PUBLIC_COOKIE_CONSENT_ENABLED === 'true' if that variable is set in the build environment.
In Payload, also enable generalSettings.cookieConsent.enabled in the plugin options to register the editor tab. The editor's Enable switch can suppress the banner. If the tab is absent, RootLayout can fall back to the developer config; tab registration is not a third runtime gate. See Project setup.
Configuration shapeLink to this section
Use the exported type rather than maintaining a local copy:
import type {
SysthemaCookieConsentConfig,
SysthemaCookieCategoryConfig,
SysthemaCookieCategoryId,
SysthemaCookieConsentTranslation,
SysthemaCookieEntry,
} from '@systhemaui/core'| Option | Purpose |
|---|---|
enabled | Master switch, disabled by default |
defaultLanguage | Fallback language, en by default |
cookie | Consent cookie name and expiresAfterDays; defaults to cc_cookie and 365 |
policyLinks | Footer links with label, url and optional newTab |
theme | Banner mode, such as default or dark with default tokens; inherit uses the document theme |
hideFromBots | Pass false to display the banner during browser automation |
guiOptions | Pass-through layout options for vanilla-cookieconsent |
reopenSelector | Defaults to a[href="#cookie-settings"]; false disables the click listener |
categories | Overrides for the five supported categories |
cookies | Cookie records with name, category, optional description, duration, party and domain |
translations | Copy keyed by language code |
scanner | Source include and exclude globs and optional databaseUrl override |
CategoriesLink to this section
| ID | Default state |
|---|---|
necessary | Enabled and read-only |
functional | Off |
analytics | Off |
performance | Off |
advertisement | Off |
Each category accepts label, description, readOnly and enabledByDefault. Custom categories are not supported. Keep optional categories opt-in unless the site's reviewed requirements say otherwise.
The integration does not map category changes to Google Consent Mode v2. If your tracking setup needs that protocol, implement and verify it separately; category-based script gating alone does not provide it.
TranslationsLink to this section
Override only the copy you need. Core merges the default English translation with the project config. Add a matching translation for every additional language you serve.
import type { SysthemaCookieConsentTranslation } from '@systhemaui/core'
export const englishConsentCopy: SysthemaCookieConsentTranslation = {
opensInNewTabLabel: '(opens in new tab)',
consentModal: {
title: 'We use cookies',
description: 'Choose which optional cookies this site can use.',
acceptAllBtn: 'Accept all',
acceptNecessaryBtn: 'Reject all',
showPreferencesBtn: 'Customize',
},
preferencesModal: {
title: 'Cookie preferences',
closeIconLabel: 'Close cookie preferences',
acceptAllBtn: 'Accept all',
acceptNecessaryBtn: 'Reject all',
savePreferencesBtn: 'Save preferences',
cookieTableHeaders: { name: 'Name', description: 'Description', duration: 'Duration' },
sections: {
necessary: { title: 'Necessary', description: 'Required for this site to function.' },
analytics: { title: 'Analytics', description: 'Measure visits when you allow them.' },
},
},
}Assign this value to cookieConsent.translations.en. preferencesModal.closeIconLabel has a built-in label for the shipped languages. consentModal.closeIconLabel is opt-in: setting it creates a banner dismiss button.
On initialization, vanilla-cookieconsent prefers <html lang> when that language, or its two-letter prefix, has a translation. Otherwise it uses the configured default, falling back to an available translation if that default is missing. You can change language later through CookieConsent.setLanguage().
In Payload, translations exposed in the editor seed the global only on first initialization. Cleared editor fields stay cleared; the developer translation does not refill them. Keys without a matching editor field continue to use the developer config. See Editing consent in Payload.
Footer compositionLink to this section
policyLinks renders links in declaration order. New-tab links use target="_blank", rel="noopener" and an accessible new-tab cue. Internal Payload page references are resolved on the server through the site's locale-aware link helpers.
Set translations.<language>.consentModal.footer to literal HTML when you need custom footer markup. That override applies per language. Otherwise Systhema composes the footer from policyLinks.
Add a persistent reopener to your site footer separately:
<a href="#cookie-settings">Cookie settings</a>Resolving the configLink to this section
For a Next.js app without Payload, use the server resolver:
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 data-theme="default" className="bg-layout-main">
<SysthemaProvider cookieConsent={cookieConsent}>{children}</SysthemaProvider>
</body>
</html>
)
}The resolver returns null when the master switch is off. On the server, it reads the merged config and .systhema/cookies.discovered.json; explicitly configured cookie names win over discovered entries. The browser implementation reads the injected in-memory config and performs no filesystem access.
For Payload, retain the starter's RootLayout and its payloadInstance prop. It resolves General Settings on the server and forwards the banner config. See Cookie consent for setup and the plain HTML limitation.