Cookie Banner
Consent banner for explaining and managing optional cookies
CookieBanner displays a consent surface, lets users choose optional cookie categories, and reports the selected keys to the application. It does not persist consent or enable analytics by itself: storage, loading decisions, and integrations remain under application control.
The component has two presentations:
bar— the default full-width surface for an application edge;card— a compact elevated card, suitable for a floating consent prompt.
Basic usage
import { CookieBanner } from '@mosmox/ui';
export function PrivacyBanner() {
const saveConsent = (categoryKeys: string[]) => {
localStorage.setItem('cookie-consent', JSON.stringify(categoryKeys));
};
return (
<CookieBanner
title="Your privacy matters"
description="We use cookies to improve the experience and measure usage."
policyHref="/privacy"
onAcceptAll={saveConsent}
onRejectAll={saveConsent}
/>
);
}The uncontrolled banner is open by default. Use defaultOpen={false} to start closed, or use open with onOpenChange when visibility is owned by the application.
Consent categories
Use categories to describe the consent groups shown in the preferences editor. Every category needs a stable key; those keys are returned by consent callbacks. required categories are always selected and rendered as disabled checkboxes. defaultChecked controls the initial selection of optional categories.
<CookieBanner
showPreferences
categories={[
{
key: 'necessary',
label: 'Necessary',
description: 'Required for security and sign-in.',
required: true,
defaultChecked: true,
},
{
key: 'analytics',
label: 'Analytics',
description: 'Anonymous product usage insights.',
defaultChecked: true,
},
{
key: 'marketing',
label: 'Marketing',
description: 'Used to personalize relevant messages.',
},
]}
onConsentChange={(keys) => setDraftConsent(keys)}
onSavePreferences={(keys) => saveConsent(keys)}
/>The reject action keeps required categories selected by default. Set allowNecessaryOnly={false} when rejection should submit an empty selection instead.
When preferences are open, the editor moves to a separate full-width row. Its controls use the framework Checkbox component, so checked, disabled, focus, and theme states match the rest of the design system.
Visibility and controlled mode
function ControlledBanner() {
const [open, setOpen] = useState(true);
return (
<CookieBanner
open={open}
onOpenChange={setOpen}
showClose
onClose={() => setOpen(false)}
/>
);
}onAcceptAll, onRejectAll, and onSavePreferences are called before the banner closes. onConsentChange is called both when a category is toggled and when a consent choice is submitted. showClose adds a dismiss action that closes the banner without submitting consent.
Programmatic API
Use CookieBannerProvider when the banner should be opened by an application service, route guard, or startup flow without placing a visible banner in feature markup.
import { CookieBannerProvider, useCookieBanner } from '@mosmox/ui';
export function AppRoot() {
return (
<CookieBannerProvider>
<App />
</CookieBannerProvider>
);
}
function AppStartup() {
const { open } = useCookieBanner();
const requestConsent = async () => {
const result = await open({
policyHref: '/privacy',
showPreferences: true,
});
if (result.action !== 'close') {
localStorage.setItem(
'cookie-consent',
JSON.stringify(result.categoryKeys),
);
}
};
return <button onClick={requestConsent}>Review cookie settings</button>;
}open(options) resolves with:
| Action | Meaning |
|---|---|
accept | The user accepted all categories. |
reject | The user rejected optional categories. |
preferences | The user saved the selected preferences. |
close | The user dismissed the banner without submitting consent. |
The result is { action, categoryKeys }. Call close() from the provider to dismiss the active programmatic banner; it resolves the request with action: 'close'.
All regular CookieBanner props can be passed to open, except open, defaultOpen, and onOpenChange, which are managed by the provider.
Layout and placement
The component supports three positioning modes and two layouts:
<CookieBanner
position="fixed"
placement="bottom"
layout="inline"
presentation="bar"
maxWidth={1120}
/>position="fixed"attaches the banner to the viewport;position="sticky"keeps it attached while its scroll container allows it;position="static"renders it in normal document flow, useful for embedded examples;placementchoosestoporbottomfor fixed and sticky modes;layout="inline"places copy and actions in one row when space allows;layout="stacked"places actions below the content;fullWidthkeeps the surface edge-to-edge;maxWidthlimits the inner content, not the viewport surface.
On small screens the component automatically stacks the content, actions, and preference categories.
Visual variants and sizes
variant accepts default, soft, and contrast. The soft variant is intentionally neutral and low contrast; it does not introduce a strong blue tint. size="sm" reduces padding and typography. The default full-width bar is flat and uses the ConfigProvider radius token at the viewport edge, while presentation="card" retains its elevated surface and responsive width.
<CookieBanner
position="static"
presentation="card"
variant="contrast"
size="sm"
maxWidth={500}
title="Cookie settings"
description="Choose which cookies you want to allow."
showClose
/>Custom content and actions
title, description, icon, and children accept ReactNode, so an application can add links, helper content, or a branded icon. actions replaces the complete built-in action area; use it when consent is handled by an existing workflow.
<CookieBanner
position="static"
presentation="card"
title="Cookie settings"
description={<>Read our <a href="/privacy">privacy policy</a>.</>}
icon={<span aria-hidden="true">🍪</span>}
actions={
<>
<Button size="sm" variant="outline">Only necessary</Button>
<Button size="sm">Accept all</Button>
</>
}
>
<small>Preferences can be changed later in account settings.</small>
</CookieBanner>The default actions use the framework Button component. The accept action is primary; manage, reject, and close actions remain secondary.
Localization
Built-in labels are available for en, uk, de, and fr. The nearest ConfigProvider locale is used unless locale is supplied directly. Application-provided titles, descriptions, category labels, and action labels are not translated automatically.
<ConfigProvider locale="uk">
<CookieBanner
title="Налаштування cookies"
description="Оберіть, які категорії cookies дозволити."
policyHref="/privacy"
policyLabel="Політика приватності"
acceptLabel="Дозволити всі"
rejectLabel="Лише необхідні"
/>
</ConfigProvider>ConfigProvider defaults and design tokens
Set shared defaults for every banner inside the provider subtree. Instance props take precedence.
<ConfigProvider
components={{
cookieBanner: {
layout: 'inline',
position: 'fixed',
placement: 'bottom',
presentation: 'bar',
size: 'default',
variant: 'default',
showPreferences: true,
radius: 8,
},
}}
>
<CookieBanner />
</ConfigProvider>If radius is not provided on the component or in components.cookieBanner, the surface uses the theme token --mm-radius-control. Custom surfaceColor, textColor, and borderColor values are available for application-specific branding.
API reference
CookieBanner props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled visibility. |
defaultOpen | boolean | true | Initial visibility in uncontrolled mode. |
onOpenChange | (open: boolean) => void | — | Called when visibility changes. |
onClose | () => void | — | Called when the banner is dismissed. |
categories | CookieBannerCategory[] | built-in categories | Categories shown in preferences. |
onAcceptAll | (keys: string[]) => void | — | Called with all category keys. |
onRejectAll | (keys: string[]) => void | — | Called with keys retained after rejection. |
onConsentChange | (keys: string[]) => void | — | Called when selected keys change. |
onSavePreferences | (keys: string[]) => void | — | Called when preferences are saved. |
allowNecessaryOnly | boolean | true | Retains required categories on rejection. |
showPreferences | boolean | provider or true | Shows the preferences action. |
showClose | boolean | false | Shows a dismiss action without consent submission. |
closeLabel | string | localized | Accessible close-button label. |
layout | 'inline' | 'stacked' | provider or inline | Content/action arrangement. |
position | 'fixed' | 'sticky' | 'static' | provider or fixed | CSS positioning mode. |
placement | 'top' | 'bottom' | provider or bottom | Viewport edge for fixed/sticky modes. |
fullWidth | boolean | true | Uses the available surface width. |
maxWidth | number | string | 1120px | Maximum inner content width. Numbers are pixels. |
presentation | 'bar' | 'card' | provider or bar | Full-width bar or floating card. |
size | 'sm' | 'default' | provider or default | Compact or standard spacing and typography. |
variant | 'default' | 'soft' | 'contrast' | provider or default | Surface treatment. |
radius | number | string | provider or --mm-radius-control | Surface border radius. Numbers are pixels. |
surfaceColor | string | theme surface | Custom CSS background color. |
textColor | string | theme text | Custom CSS text color. |
borderColor | string | theme border | Custom CSS border color. |
actions | ReactNode | built-in buttons | Replaces the complete action area. |
title | ReactNode | localized title | Banner heading. |
description | ReactNode | localized description | Consent explanation. |
icon | ReactNode | — | Optional decorative icon. |
children | ReactNode | — | Additional content below the description. |
policyHref | string | — | Privacy/cookie policy URL. |
policyLabel | ReactNode | Privacy policy | Policy link label. |
preferencesLabel | ReactNode | localized | Manage-preferences label. |
acceptLabel | ReactNode | localized | Accept-all label. |
rejectLabel | ReactNode | localized | Reject label. |
locale | 'en' | 'uk' | 'de' | 'fr' | provider or en | Built-in UI locale. |
className | string | — | Additional class name. |
style | CSSProperties | — | Additional styles and CSS custom properties. |
CookieBannerCategory
| Field | Type | Default | Description |
|---|---|---|---|
key | string | required | Stable identifier returned in callbacks. |
label | ReactNode | required | Category name. |
description | ReactNode | — | Explanation shown in preferences. |
required | boolean | false | Prevents the category from being unchecked. |
defaultChecked | boolean | false | Initial checked state. |
CookieBannerProvider
| API | Type | Description |
|---|---|---|
CookieBannerProvider | { children?: ReactNode } | Provides the programmatic banner controller. |
useCookieBanner() | CookieContextValue | Returns open and close; must be used inside the provider. |
open(options?) | (options?: CookieBannerRequest) => Promise<CookieBannerResult> | Opens a banner and resolves after accept, reject, saved preferences, or close. |
close() | () => void | Dismisses the active programmatic banner. |
CookieBannerRequest contains all CookieBannerProps except open, defaultOpen, and onOpenChange. CookieBannerResult contains action and categoryKeys; CookieBannerAction is accept | reject | preferences | close.
Accessibility
The component renders a labeled region. Buttons are keyboard accessible, the preference editor uses the framework Checkbox, required categories are disabled instead of silently mutable, and the close action has a configurable accessible label. Provide meaningful text for the title, description, policy link, and category explanations. If the banner is essential to the current flow, keep it visible until an explicit consent action rather than relying on a dismiss-only control.