Mosmox UI
Current version
GitHubnpmjs.com
Overlays

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.

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:

ActionMeaning
acceptThe user accepted all categories.
rejectThe user rejected optional categories.
preferencesThe user saved the selected preferences.
closeThe 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;
  • placement chooses top or bottom for fixed and sticky modes;
  • layout="inline" places copy and actions in one row when space allows;
  • layout="stacked" places actions below the content;
  • fullWidth keeps the surface edge-to-edge;
  • maxWidth limits 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

PropTypeDefaultDescription
openboolean—Controlled visibility.
defaultOpenbooleantrueInitial visibility in uncontrolled mode.
onOpenChange(open: boolean) => void—Called when visibility changes.
onClose() => void—Called when the banner is dismissed.
categoriesCookieBannerCategory[]built-in categoriesCategories 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.
allowNecessaryOnlybooleantrueRetains required categories on rejection.
showPreferencesbooleanprovider or trueShows the preferences action.
showClosebooleanfalseShows a dismiss action without consent submission.
closeLabelstringlocalizedAccessible close-button label.
layout'inline' | 'stacked'provider or inlineContent/action arrangement.
position'fixed' | 'sticky' | 'static'provider or fixedCSS positioning mode.
placement'top' | 'bottom'provider or bottomViewport edge for fixed/sticky modes.
fullWidthbooleantrueUses the available surface width.
maxWidthnumber | string1120pxMaximum inner content width. Numbers are pixels.
presentation'bar' | 'card'provider or barFull-width bar or floating card.
size'sm' | 'default'provider or defaultCompact or standard spacing and typography.
variant'default' | 'soft' | 'contrast'provider or defaultSurface treatment.
radiusnumber | stringprovider or --mm-radius-controlSurface border radius. Numbers are pixels.
surfaceColorstringtheme surfaceCustom CSS background color.
textColorstringtheme textCustom CSS text color.
borderColorstringtheme borderCustom CSS border color.
actionsReactNodebuilt-in buttonsReplaces the complete action area.
titleReactNodelocalized titleBanner heading.
descriptionReactNodelocalized descriptionConsent explanation.
iconReactNode—Optional decorative icon.
childrenReactNode—Additional content below the description.
policyHrefstring—Privacy/cookie policy URL.
policyLabelReactNodePrivacy policyPolicy link label.
preferencesLabelReactNodelocalizedManage-preferences label.
acceptLabelReactNodelocalizedAccept-all label.
rejectLabelReactNodelocalizedReject label.
locale'en' | 'uk' | 'de' | 'fr'provider or enBuilt-in UI locale.
classNamestring—Additional class name.
styleCSSProperties—Additional styles and CSS custom properties.

CookieBannerCategory

FieldTypeDefaultDescription
keystringrequiredStable identifier returned in callbacks.
labelReactNoderequiredCategory name.
descriptionReactNode—Explanation shown in preferences.
requiredbooleanfalsePrevents the category from being unchecked.
defaultCheckedbooleanfalseInitial checked state.

CookieBannerProvider

APITypeDescription
CookieBannerProvider{ children?: ReactNode }Provides the programmatic banner controller.
useCookieBanner()CookieContextValueReturns 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()() => voidDismisses 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.