Cookie Preferences Modal — Free HTML CSS JS Snippet

Cookie Preferences · Modals · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Fixed bottom banner: center-aligned with max-width cap at 860px
Three banner actions: Manage Preferences, Reject All, Accept All
Modal overlay with fixed backdrop at z-index: 300
4 cookie categories: Essential (required), Analytics, Marketing, Preferences
CSS toggle switches with disabled state for Essential (always on)
Accept All, Reject All, Save Preferences in both banner and modal
Confirmation status box: shown on page after banner dismissal
No external CMP library — pure HTML/CSS/JS cookie consent UI

About this UI Snippet

Cookie Preferences Modal — GDPR Consent Banner with Category Toggles

Screenshot of the Cookie Preferences snippet rendered live

A cookie preferences modal is a legal requirement for websites under GDPR (EU), CCPA (California), and similar privacy regulations. This snippet provides a complete cookie consent system: a fixed bottom banner with Accept All, Reject All, and Manage Preferences buttons; a modal overlay with per-category toggle switches (Essential, Analytics, Marketing, Preferences); and a confirmation state after any choice is saved.

The banner layout

The .banner uses position: fixed, bottom: 20px, left: 50% with transform: translateX(-50%) to centre it above the page footer. A max-width: 860px keeps it from stretching too wide on large screens. The backdrop is a fixed overlay that darkens the page when the modal is open.

The CSS toggle switches

Each cookie category uses the same CSS toggle pattern: a hidden checkbox + .track pseudo-element. The Essential Cookies toggle has disabled attribute and .disabled class — its .track background is set to a light indigo (always-on appearance) without the cursor: pointer, communicating that it cannot be changed. The other three toggles start with different default states (Analytics: on, Marketing: off, Preferences: on) to demonstrate a realistic defaults scenario.

The three action paths

Accept All checks all three optional checkboxes before calling dismiss(). Reject All unchecks all three before calling dismiss(). Save Preferences reads the current checkbox states and builds a summary message before calling dismiss(). All three then hide the banner and show the status confirmation box on the page.

GDPR compliance notes

This snippet provides the UI pattern. For actual legal compliance, integrate with a Consent Management Platform (CMP) like the GDPR consent manager or store consent preferences in a cookie: document.cookie = "consent=" + JSON.stringify({ analytics, marketing, preferences }) + "; max-age=31536000; SameSite=Lax". Only load third-party analytics/ad scripts after the user has given consent.

Conditional script injection after consent

The most important production step is ensuring that tracking scripts are never executed before the user grants the relevant consent. The standard technique is to not include script tags for Google Analytics, Facebook Pixel, or any ad network in the initial HTML. Instead, dynamically create and append script elements only inside the acceptAll() or savePrefs() callback after reading the consent flags. For Tag Manager (GTM) workflows, push a custom dataLayer event: window.dataLayer.push({ event: "cookie_consent_update", analytics_consent: "granted" }) and configure GTM triggers that fire only when this event is present. This keeps all tracking logic in GTM without code changes for future tag additions.

Re-opening the preferences modal

Users must be able to withdraw or change consent at any time under GDPR. Add a "Cookie Settings" link in your site footer that calls openModal() to re-show the modal at any time. Read the current saved consent cookie and pre-populate the toggle checkboxes to their last saved state so users see their existing choices before making changes. After they save again, overwrite the consent cookie with the new values and apply or remove scripts accordingly — marketing scripts already injected may need a page reload to fully deactivate.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to work out why the essential toggle looks locked just by staring at the CSS. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how the disabled attribute combined with the toggle.disabled class communicates "always on" both visually and functionally, and why acceptAll, reject, and savePrefs all funnel through one shared dismiss function instead of duplicating the close-and-confirm logic three times. The same assistant can help optimize it — for instance asking whether the individual getElementById calls in acceptAll and reject should be cached once rather than re-queried on every action. It's also useful for extending the panel: ask it to persist the saved category choices to a cookie with an expiry and re-render the toggles from that stored state on return visits, gate real analytics/ad script loading strictly behind the analytics and marketing flags, or add a version number to the consent record so policy changes force a re-prompt. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a granular cookie-consent system in plain HTML, CSS, and JavaScript combining a bottom banner and a detailed preferences modal — no consent-management library, no frameworks.

Requirements:
- A bottom banner shown on load with three actions: Accept All, Reject All, and Manage Preferences, the last of which opens a modal dialog with a backdrop.
- The modal must list at least four cookie categories, each with a name, a plain-language description, and its own toggle switch, where one category (Essential/Strictly Necessary) is visually marked as required, its toggle is checked and disabled so it cannot be turned off, and every bulk action (accept/reject) must explicitly skip that required category rather than trying to toggle a disabled control.
- Each toggle switch must be built from a real checkbox input (not just a styled div) paired with a sibling element that renders the visual track and knob via CSS selectors keyed off the checkbox's checked and disabled states, so the switches remain keyboard-operable and screen-reader friendly.
- Three actions in the modal footer — Reject All, Save Preferences, Accept All — where Accept All checks every non-required category, Reject All unchecks every non-required category, and Save Preferences reads whatever the current toggle states are without changing them, and all three must funnel through one shared function that closes both the modal and the banner and shows a single confirmation message summarizing exactly which categories ended up enabled.
- The confirmation message must be built dynamically from the actual current checkbox states at the moment the user acts, not from a hardcoded string, so it always accurately reflects what was consented to.
- Structure the code so that the confirmation/save step is the one clear place where a real implementation would persist the choice (e.g. to a cookie) and conditionally load third-party analytics or marketing scripts only for the categories the user actually enabled.

Step by step

How to Use

  1. 1
    See the banner on page loadThe cookie banner appears fixed at the bottom of the page. It has three buttons: Manage Preferences, Reject All, and Accept All.
  2. 2
    Open the preferences modalClick "Manage Preferences" to open the modal with four cookie categories. Essential is always on. Toggle Analytics, Marketing, and Preferences independently.
  3. 3
    Save, Accept, or RejectClick "Save Preferences" to save your current toggle states. "Accept All" turns on all optional categories. "Reject All" turns them all off. The banner dismisses and a confirmation appears on the page.
  4. 4
    Persist consent to a cookieIn the dismiss() function, save the consent state: document.cookie = "consent=" + JSON.stringify({ analytics, marketing, preferences }) + "; max-age=31536000". On page load, read this cookie and skip showing the banner if it exists.
  5. 5
    Load scripts conditionally on consentAfter accept/save, check each consent flag before injecting analytics or marketing scripts: if (analytics) { const s = document.createElement("script"); s.src = "https://www.google-analytics.com/analytics.js"; document.head.appendChild(s); }
  6. 6
    Export for your frameworkClick "JSX" for a React component with useState for modal open state and toggle values. Click "Vue" for a Vue 3 SFC with reactive consent object.

Real-world uses

Common Use Cases

GDPR cookie consent for EU-targeted web apps
Required for any website with EU visitors that uses tracking cookies (Google Analytics, Facebook Pixel, Hotjar, etc.). Wire the consent choices to conditional script loading: only inject third-party scripts after the user grants consent for that category.
Privacy-first SaaS onboarding with consent step
Show the preferences modal as part of account creation rather than a banner — step 3 of 5 in the onboarding flow. This is cleaner than a banner and gets explicit, documented per-category consent at signup time.
E-commerce site cookie management for ad tracking
Marketing cookies control Facebook Pixel, Google Ads, and retargeting pixels. Reject All compliance means these scripts are not loaded when rejected. Wire Marketing consent flag to conditional Facebook Pixel init: if (consent.marketing) { fbq("init", "PIXEL_ID"); }
Integrate with a backend consent audit log
POST consent choices to /api/consent on save: { userId, analytics, marketing, preferences, timestamp, ip }. This creates an audit trail for compliance with GDPR Art. 7 (documented consent). Store in a separate consent_logs table, never in the main user record.
Study fixed positioning, modal overlays, and CSS toggles
The snippet demonstrates three layout techniques: fixed bottom banner positioning, a modal dialog with backdrop overlay at higher z-index, and the CSS toggle switch pattern (hidden checkbox + pseudo-element track). These patterns are foundational for cookie banners, dialogs, and drawers.
Cookie-free analytics with consent-aware fallback
Use the Marketing and Analytics consent flags to switch between full tracking and privacy-respecting alternatives: Plausible.io or Fathom (no cookies, no consent required) vs. Google Analytics (requires consent). Show different tracking scripts based on the consent state.

Got questions?

Frequently Asked Questions

Use a cookie: document.cookie = "cookie_consent=" + JSON.stringify({ analytics: true, marketing: false, preferences: true }) + "; max-age=31536000; path=/; SameSite=Lax". On DOMContentLoaded, read with document.cookie and skip showing the banner if "cookie_consent=" is found. Parse with JSON.parse(cookieVal) to get the per-category choices.

The UI meets the visual and functional requirements (prior consent, granular controls, easy rejection, no pre-ticked marketing boxes). Legal compliance also requires: storing a dated consent record linked to the user, a privacy policy link, ability to withdraw consent, and only loading tracking scripts after consent. Consult a lawyer or use a full CMP for regulated environments.

In acceptAll() or savePrefs(), check analytics consent: if (analytics) { window.dataLayer = window.dataLayer || []; function gtag(){ dataLayer.push(arguments); } gtag("js", new Date()); gtag("config", "GA_ID"); const s = document.createElement("script"); s.src = "https://www.googletagmanager.com/gtag/js?id=GA_ID"; s.async = true; document.head.appendChild(s); }

In React, manage state with const [visible, setVisible] = useState(true) for the banner, const [modalOpen, setModalOpen] = useState(false), and const [prefs, setPrefs] = useState({ analytics: true, marketing: false, preferences: true }). Read persisted consent from localStorage on mount in useEffect. In Vue 3, use ref(true) for bannerVisible and a reactive() object for prefs. In Angular, create a CookieConsentService with BehaviorSubject<ConsentPrefs> and inject it into your app root component. All three frameworks follow the same pattern: read → show banner if no saved consent → save on user action.