More Modals Snippets
Cookie Preferences Modal — Free HTML CSS JS Snippet
Cookie Preferences · Modals · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Cookie Preferences Modal — GDPR Consent Banner with Category Toggles

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:
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
- 1See 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.
- 2Open the preferences modalClick "Manage Preferences" to open the modal with four cookie categories. Essential is always on. Toggle Analytics, Marketing, and Preferences independently.
- 3Save, 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.
- 4Persist 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.
- 5Load 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); }
- 6Export 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
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.