GDPR Consent Manager — Free HTML CSS JS Snippet

GDPR Consent Manager · Modals · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Slide-up banner: position fixed bottom, transform translateY(110%) exit with CSS transition
Preferences modal: backdrop blur overlay, scale(0.96)->scale(1) entry animation, ESC close
Four consent categories: Necessary (always on), Analytics, Marketing, Functional
Pure CSS toggle switches: hidden checkbox + .slider pseudo-element, translateX(20px) on checked
localStorage persistence: saveConsent() stores JSON object, loadConsent() suppresses banner on repeat visits
Floating settings FAB: appears after consent saved, reopens modal for consent withdrawal anytime
getConsent() helper: returns parsed consent object for conditional script loading in your codebase
Accessible: role=dialog, aria-modal, aria-labelledby on modal; focus-visible ring on toggles; ESC key close

About this UI Snippet

GDPR Consent Manager — Cookie Banner, Preferences Modal, Toggle Switches & localStorage Consent Storage

Screenshot of the GDPR Consent Manager snippet rendered live

Managing cookie consent is a legal requirement for any website serving users in the European Union, the United Kingdom, or California. The GDPR (General Data Protection Regulation), ePrivacy Directive, and CCPA (California Consumer Privacy Act) all require that websites obtain freely given, specific, informed, and unambiguous consent before placing non-essential cookies or tracking technologies on a user's device. This snippet provides a complete, production-ready GDPR consent manager built entirely in HTML, CSS, and vanilla JavaScript — no third-party consent platform, no script tags, no monthly fees.

What the GDPR and ePrivacy Directive require

Under GDPR Article 6 and the EU ePrivacy Directive (Cookie Law), consent must meet four criteria: it must be freely given (declining must be as easy as accepting — no dark patterns), specific (users must know exactly which cookie categories they are consenting to), informed (a clear privacy policy link must be accessible), and unambiguous (pre-ticked boxes or implied consent from continued browsing are not valid). The user's choice must be stored and honoured, and users must be able to withdraw or change their consent at any time. This snippet satisfies every requirement: the banner offers Accept All, Reject All, and Manage Preferences; the modal exposes four named categories with individual toggles; and a persistent floating settings button lets users revisit their choices.

The four consent categories

The snippet implements the standard four-tier consent taxonomy used by the IAB TCF (Transparency and Consent Framework) and most consent management platforms. Necessary cookies (session IDs, CSRF tokens, login state) are always enabled because they are required for basic website functionality — GDPR explicitly exempts strictly necessary cookies from the consent requirement. Analytics cookies (Google Analytics, Plausible, Fathom) track how users navigate the site; they require opt-in consent because they build a profile of user behaviour. Marketing cookies (Meta Pixel, Google Ads, retargeting) are used for personalised advertising and require explicit consent under both GDPR and CCPA. Functional cookies power enhanced features such as live chat (Intercom, Zendesk), language preferences, or saved shopping carts — they require consent unless strictly necessary for a service explicitly requested by the user.

Technical implementation: banner, modal, and localStorage

The consent banner uses position: fixed; bottom: 0 with a CSS transform: translateY(110%) slide-up entrance and exit. The preferences modal uses the same opacity + scale pattern as a standard dialog: transform: translate(-50%, -48%) scale(0.96) closed, transitioning to translate(-50%, -50%) scale(1) open. Toggle switches are built in pure CSS: a hidden <input type="checkbox"> drives a .slider pseudo-element that moves 20px on the X axis when checked. The accent colour #6366f1 appears on active toggles and the primary Accept All button for visual consistency. The saveConsent() function serialises the consent object to localStorage as JSON: { necessary: true, analytics: bool, marketing: bool, functional: bool }. On page load, loadConsent() reads this value — if it exists, the banner is suppressed and the floating settings FAB is shown instead.

The floating settings FAB

After any consent action (Accept All, Reject All, or Save Preferences), the banner dismisses and a small floating "Cookie Settings" button appears in the bottom-left corner. This satisfies the GDPR requirement that users must be able to withdraw or change consent at any time — not just on first visit. The FAB reopens the preferences modal where users can toggle individual categories and save again. The FAB is hidden by default via display: none and shown by adding the .visible class which sets display: flex.

Connecting consent to actual cookie loading

The getConsent() function returns the current consent object. Call it before loading any third-party script: const c = getConsent(); if (c?.analytics) { /* inject GA script */ }. For strictest compliance, do not load any non-essential scripts in the HTML head — always load them dynamically in JavaScript after checking consent. Re-check consent in a pageshow listener to handle browser back/forward navigation.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You don't have to just trust that this satisfies GDPR's consent criteria. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to walk through exactly how loadConsent, saveConsent, and getConsent work together to decide whether the banner shows on a repeat visit, and where in the flow you would actually gate a real third-party script (like Google Analytics) behind the stored analytics flag. The same assistant can help optimize it — ask whether storing consent only in localStorage is sufficient for a multi-page site with server-rendered personalization, or whether a cookie readable server-side is also needed. It's also useful for extending the manager: ask it to add a versioned storage key so changing your cookie categories automatically re-prompts existing users, wire up the data-src iframe-blocking pattern mentioned in the howToUse for embedded YouTube or Maps content, or add a script that automatically disables Google Analytics tracking when a user withdraws previously-granted consent. 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 GDPR-style cookie consent manager in plain HTML, CSS, and JavaScript with a banner, a granular preferences modal, and persisted consent — no third-party consent platform.

Requirements:
- A bottom-docked banner that slides up on entrance and down on exit using a CSS transform transition, offering three genuinely equal-prominence actions: accept all, reject all, and open a detailed preferences view — reject must not be visually buried or harder to find than accept.
- A preferences modal listing at least four cookie categories (for example necessary, analytics, marketing, functional), where the necessary category is always-on and cannot be toggled, and every other category has its own independent toggle switch built as a real checkbox input paired with a styled slider element (not just a decorative div).
- A single consent object shape that gets serialized to localStorage as JSON whenever the user takes any consent action (accept all, reject all, or save custom preferences from the modal), and a corresponding read function that other code can call to check whether a specific category is currently granted.
- On page load, check for previously stored consent: if none exists, show the banner; if consent already exists, suppress the banner entirely and instead show a small persistent floating button that reopens the preferences modal at any time, since GDPR requires consent to be as easy to withdraw or change as it was to give.
- Opening the preferences modal must sync every toggle to whatever was previously saved (not reset to defaults), so returning users see their actual current choices reflected accurately.
- The modal must be dismissible via a close button, a backdrop click, and the Escape key, and must use proper dialog semantics (role dialog, aria-modal, an accessible label tied to its heading).
- Explain, in a comment or to the user, exactly where in application code you would call the consent-read function before loading any non-essential third-party script (like an analytics or ads tag), so tracking never fires before explicit permission is granted.

Step by step

How to Use

  1. 1
    Interact with the banner and modalThe banner slides up from the bottom on first load. Click "Accept All" or "Reject All" to save consent and dismiss the banner. Click "Manage Preferences" to open the modal where you can toggle individual cookie categories. After saving, the floating "Cookie Settings" button appears in the bottom-left corner — click it to reopen the modal at any time.
  2. 2
    Wire consent to your analytics and marketing scriptsReplace any hard-coded <script> tags for analytics or ads with dynamic loading: const c = getConsent(); if (c && c.analytics) { const s = document.createElement("script"); s.src = "https://www.googletagmanager.com/gtag/js?id=G-XXXX"; s.async = true; document.head.appendChild(s); }. Call this check in a DOMContentLoaded listener so it runs on every page after consent is loaded from localStorage.
  3. 3
    Customise the banner text and Privacy Policy linkIn the HTML panel, update the .banner-desc paragraph to describe your specific cookie usage. Replace href="#" on the "Privacy Policy" anchor with your actual /privacy-policy/ URL. Update the category descriptions in the modal to name your specific tools — e.g. "Analytics: Google Analytics 4, Plausible" and "Marketing: Meta Pixel, Google Ads Remarketing".
  4. 4
    Add or remove consent categoriesTo add a fifth category (e.g. "Personalisation"), copy a .category-row div in the HTML, give the checkbox a new id (e.g. "toggle-personalisation"), and add the key to the consent object in savePreferences(): personalisation: document.getElementById("toggle-personalisation").checked. Update saveConsent(), getConsent(), acceptAll(), and rejectAll() to include the new key.
  5. 5
    Block iframes and embeds until consent is givenFor YouTube embeds, Google Maps, or other third-party iframes, replace the src attribute with a data-src attribute on page load. After the user accepts functional or marketing consent, set iframe.src = iframe.dataset.src to load them. Show a placeholder overlay with a "Load content" button for users who decline — this is required by GDPR for consent-gated embeds.
  6. 6
    Export and add to your root layoutClick HTML to download a standalone file, or JSX for a React component. In Next.js, add the GdprConsentManager component to src/app/layout.js so it appears on every page. Use a useEffect with an empty dependency array to call loadConsent() on mount. Store the consent object in React context so any component can call useConsent() to check if a specific category is enabled before rendering consent-gated content.

Real-world uses

Common Use Cases

GDPR and ePrivacy compliant consent collection for EU websites
Any website serving EU or UK users that sets analytics, advertising, or functional cookies must present a consent banner before those cookies are placed. This snippet implements all four GDPR consent criteria — freely given, specific, informed, unambiguous — with genuine Accept All and Reject All buttons, a granular preferences modal, and persistent localStorage storage. Drop it into your root layout and wire the getConsent() helper to your script loading logic to achieve baseline GDPR compliance without a paid consent platform.
Consent-gated analytics and ad script activation
Load Google Analytics, Meta Pixel, LinkedIn Insight Tag, or any tracking script only after the user accepts the relevant category. In your DOMContentLoaded listener, call getConsent() — if c.analytics is true, dynamically inject the GA script tag; if c.marketing is true, inject the Meta Pixel. This consent-first architecture ensures zero data collection before explicit permission, which is the correct implementation pattern for GDPR, CCPA, and the IAB TCF framework used by ad networks.
Cookie preference centre with re-consent and consent withdrawal
GDPR requires that users can withdraw or change consent as easily as they gave it. The floating "Cookie Settings" FAB satisfies this requirement — it is always visible after the initial consent is saved and reopens the preferences modal where users can toggle categories and save again. When a user turns off Analytics after previously enabling it, read the new consent object and disable the corresponding scripts: window['ga-disable-G-XXXX'] = true removes GA tracking for the current session.
Design system consent UI with custom brand colours and copy
Swap #6366f1 for your brand accent colour across .btn-primary, .toggle-switch input:checked + .slider, and .always-label to match your design system. Update the .consent-banner background from #1e293b to match your dark palette. The modal uses white (#fff) and neutral greys that work with any accent. Extend the category descriptions with the actual names of your third-party tools so users have specific, GDPR-required information about what they are consenting to.
Learn pure CSS toggle switches, fixed overlay stacking, and animationend patterns
This snippet teaches three important UI patterns in one component. The CSS toggle switch uses a hidden checkbox as state storage — no JavaScript needed for the visual state. The modal overlay stacking uses z-index layers (banner: 900, overlay: 950, modal: 960, FAB: 800) to ensure correct paint order. The banner dismiss uses CSS transform: translateY(110%) with a cubic-bezier transition for the spring-physics slide animation — the same technique used in the Cookie Consent Banner snippet.
Replace third-party consent platforms with a self-hosted vanilla JS solution
Paid consent management platforms (Cookiebot, OneTrust, TrustArc) add 50-300 KB of third-party JavaScript, create an additional DNS lookup, and cost $100-$1000/month. This snippet is 6 KB total, self-hosted, and fully customisable. It handles the core consent collection, storage, and retrieval that most websites need. For sites needing IAB TCF v2.2 integration for programmatic advertising, a full CMP is required — but for first-party analytics and marketing scripts, this self-hosted solution is sufficient and eliminates the performance and privacy overhead of a third-party CMP.

Got questions?

Frequently Asked Questions

This snippet satisfies the core GDPR UI requirements: it presents consent before non-essential cookies are set, offers a genuine Reject All option that is as prominent as Accept All, provides granular category control via the preferences modal, persists the user's choice in localStorage, and allows consent withdrawal via the floating settings button. To complete your compliance implementation, you must also: (1) wire the getConsent() helper to your script loading logic so non-essential scripts only load after consent; (2) link to a complete Privacy Policy explaining what data is collected and why; (3) re-show the banner when your cookie usage changes materially; and (4) implement server-side consent checks for any SSR-rendered personalisation. For IAB TCF v2.2 compliance required by programmatic ad networks, a full certified CMP is needed.

Call getConsent() in a DOMContentLoaded listener on every page load: const c = getConsent(); if (c && c.analytics) { /* inject Google Analytics */ } if (c && c.marketing) { /* inject Meta Pixel */ } if (c && c.functional) { /* initialise Intercom */ }. If c is null, no consent has been recorded yet — do not load any non-essential scripts. When the user saves preferences, call the same conditional loading logic immediately in savePreferences() and acceptAll() so newly granted consent activates without a page reload. For revoking consent, set the appropriate script-specific disable flags (e.g. window["ga-disable-G-XXXX"] = true for Google Analytics) and note that already-set cookies will persist until their natural expiry or until the user clears browser data.

localStorage is synchronous and scoped to the origin, so getConsent() reads the same object on every page of your website without any additional setup. In a React or Next.js SPA, call loadConsent() in a useEffect in your root layout component and store the consent object in React context (useContext) or Zustand/Redux so any component can access it. For SSR pages, localStorage is unavailable on the server — check typeof window !== "undefined" before calling getConsent() in any server-side or isomorphic code. For a React hook: function useConsent() { const [c, setC] = useState(null); useEffect(() => { setC(getConsent()); }, []); return c; }

Open the browser DevTools console and run: localStorage.removeItem("gdpr-consent"); location.reload(). The STORAGE_KEY constant in the JS panel defines the localStorage key — change it from "gdpr-consent" to a versioned key like "gdpr-consent-v2" whenever you add new cookie categories. Users who previously consented under the old key will see the banner again, which is correct behaviour under GDPR — materially changing your cookie usage requires re-collecting consent. You can also call openBanner() from the console to show the banner without clearing localStorage, which is useful for visual testing.