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
| Attribute | Values | Default | Description |
|---|---|---|---|
persist |
string | consent-banner |
localStorage key for storing consent |
position |
"bottom", "top", "center" |
bottom |
Banner position. Center uses modal dialog. |
trigger |
string | — | CSS selector for a re-open button (e.g. #manage-cookies) |
expires |
string | 365 |
Days until consent expires. 0 or 'never' disables expiry. |
Required Structure
| Element | Required | Description |
|---|---|---|
<dialog> |
yes | Banner container — shown until consent is given |
<button value="accept"> |
yes | Accept-all action button |
<button value="reject"> |
no | Reject-all action button (optional) |
<input type="checkbox"> |
no | Granular preference toggles (optional, for save mode) |
<button value="save"> |
no | Save granular preferences button (optional, used with checkboxes) |
Child Attributes
| Attribute | On | Values | Description |
|---|---|---|---|
value |
button |
"accept", "reject", "save" |
Action button type — accept all, reject all, or save granular preferences |
name |
input[type=checkbox] |
string | Preference 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.