Vanilla Breeze

consent-banner

Cookie and privacy consent banner. Non-modal (bottom/top) or modal (center) dialog backed by localStorage.

Overview

The <consent-banner> component wraps a native <dialog> to handle cookie and privacy consent. It manages localStorage persistence, expiry, and provides a trigger attribute to let users re-open their preferences from anywhere on the page.

The author controls all content inside the dialog — the component handles the plumbing: show/hide, localStorage read/write, and event dispatch.

Simple Banner

The minimal setup: a <dialog> with a paragraph and footer containing accept/reject buttons. The value attribute on each button drives the consent logic.

Granular Preferences

Add checkboxes for per-category control. The value="save" button stores whatever the user has checked. The value="accept" button marks everything true; value="reject" only keeps disabled checkboxes (typically Necessary) as true.

Position Variants

The position attribute controls where the banner appears and whether it is modal.

Value Behavior Dialog API
bottom (default) Fixed to viewport bottom, page remains interactive dialog.show()
top Fixed to viewport top, page remains interactive dialog.show()
center Centered modal with backdrop — user must choose (ESC prevented) dialog.showModal()

Re-opening Preferences

Set trigger to a CSS selector pointing at a Manage Cookies button (or link) elsewhere on the page. When clicked, the dialog re-opens with previously saved checkbox states restored.

The trigger uses document-level event delegation, so the target element can exist anywhere in the DOM — even if it loads after the banner.

Events

The component dispatches a single event when the user makes a consent choice.

Event Detail Description
consent-banner:change { preferences: Object, action: string } Fired when the user clicks accept, reject, or save. preferences maps checkbox names to booleans. action is the button’s value.

Static API

The ConsentBanner class exposes static methods for reading and clearing consent from external code.

Method Parameters Returns Description
ConsentBanner.getConsent(key?) key: string (default: 'consent-banner') { preferences, action, timestamp } | null Read stored consent. Use on page load to check if analytics/marketing scripts should run.
ConsentBanner.reset(key?) key: string (default: 'consent-banner') void Clear stored consent. The banner reappears on next page load.

Attributes Reference

AttributeValuesDefaultDescription
persiststringconsent-bannerlocalStorage key for storing consent
position"bottom", "top", "center"bottomBanner position. Center uses modal dialog.
triggerstringCSS selector for a re-open button (e.g. #manage-cookies)
expiresstring365Days until consent expires. 0 or 'never' disables expiry.

Required Structure

ElementRequiredDescription
<dialog>yesBanner container — shown until consent is given
<button value="accept">yesAccept-all action button
<button value="reject">noReject-all action button (optional)
<input type="checkbox">noGranular preference toggles (optional, for save mode)
<button value="save">noSave granular preferences button (optional, used with checkboxes)

Child Attributes

AttributeOnValuesDescription
valuebutton"accept", "reject", "save"Action button type — accept all, reject all, or save granular preferences
nameinput[type=checkbox]stringPreference category name stored in the consent cookie

localStorage Format

Consent is stored as JSON under the configured key.

The timestamp field enables expiry. When expires days have elapsed since the timestamp, the banner reappears on next page load.

Accessibility

Dialog Behavior

  • Bottom / Top: Uses dialog.show() (non-modal). The page remains interactive — users can scroll and navigate freely.
  • Center: Uses dialog.showModal() (modal). Focus is trapped inside the dialog. ESC is prevented to enforce a consent choice.

Keyboard

Key Action
Tab Move between buttons and checkboxes
Enter / Space Activate button or toggle checkbox
Escape Prevented in center (modal) position; no effect in bottom/top (non-modal)

Reduced Motion

When prefers-reduced-motion: reduce is set, the slide-in animation is disabled. The banner appears instantly.

No JavaScript

The consent-banner:not(:defined) CSS rule hides the banner until the component is defined. Without JavaScript, the banner never appears and no consent is required — a safe progressive enhancement default.

Scope

This is a client-side consent UI helper built around native <dialog>. It stores the user's decision in localStorage. If your project requires a broader compliance workflow (server-side enforcement, cookie-less tracking prevention, or jurisdiction-specific legal requirements), those concerns live outside this component.