Cookie Consent

GDPR-compliant cookie consent management with multiple categories, persistence, and customizable styling

Overview

GDPR-compliant cookie consent management with full customization options. The Cookie Consent component provides a flexible, user-friendly interface for managing cookie preferences with support for multiple categories, persistence, and customizable styling.

Key Features

  • GDPR and CCPA compliant cookie management
  • Customizable cookie categories (necessary, performance, marketing, etc.)
  • Multiple position and layout options
  • localStorage persistence with configurable expiry
  • Light and dark theme support
  • Config Engine compatible for declarative setup
  • Promise-based API for programmatic control
  • Reopen trigger support for preference management

When to Use Cookie Consent

  • Legal Compliance: Required for GDPR compliance in EU regions
  • User Privacy: Giving users control over their data
  • Analytics Management: Conditional loading of tracking scripts
  • Marketing Tools: Managing third-party advertising cookies
  • Personalization: Storing user preferences with consent

Basic Usage

// Initialize cookie consent
const consent = Domma.elements.cookieConsent({
    message: 'We use cookies to improve your experience.',
    privacyPolicyUrl: '/privacy',
    onAccept: (preferences) => {
        console.log('Cookies accepted:', preferences);
    }
});

// Show the consent bar
consent.show();

Getting Started

Add GDPR-compliant cookie consent to your page in two simple steps

Step 1: Include Domma

Add Domma CSS and JavaScript to your page:

<!-- CSS -->
<link rel="stylesheet" href="dist/domma.css">
<link rel="stylesheet" href="dist/elements.css">

<!-- JavaScript -->
<script src="dist/domma.min.js"></script>

Step 2: Initialize Cookie Consent

Call Domma.elements.cookieConsent() to create and show the consent banner:

const consent = Domma.elements.cookieConsent({
    message: 'We use cookies to improve your experience.',
    privacyPolicyUrl: '/privacy-policy',
    autoShow: true,   // Automatically show on page load
    onAccept: (preferences) => {
        // User accepted cookies
        console.log('Accepted:', preferences);
    },
    onReject: () => {
        // User rejected cookies
        console.log('Cookies rejected');
    }
});

Note: The cookie consent component auto-generates the consent UI (no HTML required). It handles storage of user preferences in localStorage, respects user choices, and provides callbacks for when cookies are accepted or rejected. Set autoShow: true to display automatically on page load.

Basic Examples

Example 1: Simple Consent Bar

Simple cookie consent bar at the bottom of the page with default settings.

Example 1: Simple Consent Bar
Status: Not initialized
Preferences: {}
<button type="button" class="btn btn-primary" data-action="1">Show Basic Consent</button>
<button type="button" class="btn btn-outline" data-action="2">Reset Consent</button>
Status: <span id="basic-state">Not initialized</span><br>
Preferences: <span id="basic-prefs">{}</span>
/**
 * Example 1: Simple Consent Bar - from public/showcase/elements/cookie-consent.
 */
export function mount(root) {
    let basicConsent, customConsent, positionConsent, apiConsent;
      // Basic consent example
    function showBasicConsent() {
        if (basicConsent) basicConsent.destroy();

        basicConsent = E.cookieConsent({
          message: 'We use cookies to improve your experience on our site.',
          privacyPolicyUrl: '#',
          storageKey: 'demo-basic-consent',
          autoShow: false,
          onAccept: (preferences) => {
            updateBasicStatus();
          },
          onReject: () => {
            updateBasicStatus();
          },
          onChange: () => {
            updateBasicStatus();
          }
        });

        basicConsent.show();
        updateBasicStatus();
      }
    function resetBasicConsent() {
        if (basicConsent) {
          basicConsent.reset();
          basicConsent.show();
          updateBasicStatus();
        }
      }
    function updateBasicStatus() {
        if (basicConsent) {
          $(root).find('#basic-state').text(basicConsent.getState());
          $(root).find('#basic-prefs').text(JSON.stringify(basicConsent.getPreferences(), null, 2));
        }
      }
      // Custom categories example
    function showCustomCategories() {
        if (customConsent) customConsent.destroy();

        customConsent = E.cookieConsent({
          message: 'We value your privacy. Choose which cookies you allow.',
          categories: {
            necessary: {
              label: 'Essential Cookies',
              description: 'These cookies are required for the website to function properly.',
              required: true
            },
            performance: {
              label: 'Performance Cookies',
              description: 'These cookies help us understand how you interact with our website.',
              required: false
            },
            marketing: {
              label: 'Marketing Cookies',
              description: 'These cookies are used to deliver personalized advertisements.',
              required: false
            }
          },
          privacyPolicyUrl: '#',
          storageKey: 'demo-custom-consent',
          autoShow: false,
          onAccept: (preferences) => {
            updateCustomStatus();
          },
          onChange: () => {
            updateCustomStatus();
          }
        });

        customConsent.show();
        updateCustomStatus();
      }
    function resetCustomCategories() {
        if (customConsent) {
          customConsent.reset();
          customConsent.show();
          updateCustomStatus();
        }
      }
    function updateCustomStatus() {
        if (customConsent) {
          $(root).find('#custom-state').text(customConsent.getState());
          $(root).find('#custom-prefs').text(JSON.stringify(customConsent.getPreferences(), null, 2));
        }
      }
      // Position examples
    function showPosition(position, layout) {
        if (positionConsent) positionConsent.destroy();

        const theme = position === 'top' || position === 'bottom' ? 'dark' : 'light';

        positionConsent = E.cookieConsent({
          message: `This is a ${position} ${layout} consent.`,
          position: position,
          layout: layout,
          theme: theme,
          backdrop: layout === 'modal',
          privacyPolicyUrl: '#',
          storageKey: 'demo-position-consent',
          autoShow: false
        });

        positionConsent.show();
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        showBasicConsent();
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        resetBasicConsent();
    });
}
// Basic cookie consent
const consent = Domma.elements.cookieConsent({
    message: 'We use cookies to improve your experience.',
    privacyPolicyUrl: '/privacy',
    storageKey: 'demo-basic-consent',
    autoShow: false,
    onAccept: (preferences) => {
        console.log('Cookies accepted:', preferences);
    }
});

consent.show();

Custom Categories

Granular Cookie Control

Cookie consent with customizable categories for granular control.

Granular Cookie Control
Status: Not initialized
Preferences: {}
<button type="button" class="btn btn-primary" data-action="1">Show Custom Categories</button>
<button type="button" class="btn btn-outline" data-action="2">Reset Consent</button>
Status: <span id="custom-state">Not initialized</span><br>
Preferences: <span id="custom-prefs">{}</span>
/**
 * Granular Cookie Control - from public/showcase/elements/cookie-consent.
 */
export function mount(root) {
    let basicConsent, customConsent, positionConsent, apiConsent;
      // Custom categories example
    function showCustomCategories() {
        if (customConsent) customConsent.destroy();

        customConsent = E.cookieConsent({
          message: 'We value your privacy. Choose which cookies you allow.',
          categories: {
            necessary: {
              label: 'Essential Cookies',
              description: 'These cookies are required for the website to function properly.',
              required: true
            },
            performance: {
              label: 'Performance Cookies',
              description: 'These cookies help us understand how you interact with our website.',
              required: false
            },
            marketing: {
              label: 'Marketing Cookies',
              description: 'These cookies are used to deliver personalized advertisements.',
              required: false
            }
          },
          privacyPolicyUrl: '#',
          storageKey: 'demo-custom-consent',
          autoShow: false,
          onAccept: (preferences) => {
            updateCustomStatus();
          },
          onChange: () => {
            updateCustomStatus();
          }
        });

        customConsent.show();
        updateCustomStatus();
      }
    function resetCustomCategories() {
        if (customConsent) {
          customConsent.reset();
          customConsent.show();
          updateCustomStatus();
        }
      }
    function updateCustomStatus() {
        if (customConsent) {
          $(root).find('#custom-state').text(customConsent.getState());
          $(root).find('#custom-prefs').text(JSON.stringify(customConsent.getPreferences(), null, 2));
        }
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        showCustomCategories();
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        resetCustomCategories();
    });
}
// Custom categories
const consent = Domma.elements.cookieConsent({
    categories: {
        necessary: {
            label: 'Essential Cookies',
            description: 'Required for core functionality.',
            required: true
        },
        performance: {
            label: 'Performance Cookies',
            description: 'Help us improve site speed.',
            required: false
        },
        marketing: {
            label: 'Marketing Cookies',
            description: 'Used for targeted advertising.',
            required: false
        }
    },
    onAccept: (preferences) => {
        // Handle category-specific preferences
        if (preferences.performance) {
            // Enable performance tracking
        }
        if (preferences.marketing) {
            // Enable marketing cookies
        }
    }
});

Position & Layout Variants

Position Options

Different positions and layouts for the cookie consent UI.

Position Options
<button type="button" class="btn btn-outline" data-action="1">Bottom Bar</button>
<button type="button" class="btn btn-outline" data-action="2">Top Bar</button>
<button type="button" class="btn btn-outline" data-action="3">Bottom Left Box</button>
<button type="button" class="btn btn-outline" data-action="4">Bottom Right Box</button>
<button type="button" class="btn btn-outline" data-action="5">Center Modal</button>
/**
 * Position Options - from public/showcase/elements/cookie-consent.
 */
export function mount(root) {
    let basicConsent, customConsent, positionConsent, apiConsent;
      // Position examples
    function showPosition(position, layout) {
        if (positionConsent) positionConsent.destroy();

        const theme = position === 'top' || position === 'bottom' ? 'dark' : 'light';

        positionConsent = E.cookieConsent({
          message: `This is a ${position} ${layout} consent.`,
          position: position,
          layout: layout,
          theme: theme,
          backdrop: layout === 'modal',
          privacyPolicyUrl: '#',
          storageKey: 'demo-position-consent',
          autoShow: false
        });

        positionConsent.show();
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        showPosition('bottom', 'bar');
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        showPosition('top', 'bar');
    });
    $(root).find('[data-action="3"]').on('click', function (event) {
        showPosition('bottom-left', 'box');
    });
    $(root).find('[data-action="4"]').on('click', function (event) {
        showPosition('bottom-right', 'box');
    });
    $(root).find('[data-action="5"]').on('click', function (event) {
        showPosition('center-modal', 'modal');
    });
}
// Position variants
Domma.elements.cookieConsent({
    position: 'bottom-right',  // or 'top', 'bottom-left', 'center-modal'
    layout: 'box',             // or 'bar', 'modal'
    theme: 'dark',             // or 'light', 'auto'
    animation: true,
    backdrop: true             // For modal layout
});

Config Engine Integration

Declarative Setup

Initialize cookie consent using Domma's declarative config engine.

Declarative Setup
<button type="button" class="btn btn-primary" data-action="1">Show Config Example</button>
/**
 * Declarative Setup - from public/showcase/elements/cookie-consent.
 */
export function mount(root) {
      // Config example
    function showConfigExample() {
        $.setup({
          'body': {
            component: 'cookieConsent',
            options: {
              message: 'This consent was created using the Config Engine.',
              position: 'bottom-left',
              layout: 'box',
              theme: 'dark',
              privacyPolicyUrl: '#',
              cookiePolicyUrl: '#',
              storageKey: 'demo-config-consent',
              autoShow: true
            }
          }
        });
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        showConfigExample();
    });
}
// Using Config Engine
$.setup({
    'body': {
        component: 'cookieConsent',
        options: {
            message: 'This site uses cookies...',
            categories: {
                analytics: {
                    label: 'Analytics',
                    description: 'Help us understand usage',
                    required: false
                }
            },
            privacyPolicyUrl: '/privacy-policy',
            position: 'bottom',
            theme: 'dark',
            onAccept: (preferences) => {
                console.log('Configured consent accepted:', preferences);
            }
        }
    }
});

API Methods

Programmatic Control

Full programmatic control of the cookie consent component.

Programmatic Control
API output will appear here...
<button type="button" class="btn btn-outline" data-action="1">show()</button>
<button type="button" class="btn btn-outline" data-action="2">hide()</button>
<button type="button" class="btn btn-outline" data-action="3">accept()</button>
<button type="button" class="btn btn-outline" data-action="4">reject()</button>
<button type="button" class="btn btn-outline" data-action="5">showCustomize()</button>
<button type="button" class="btn btn-outline" data-action="6">getState()</button>
<button type="button" class="btn btn-outline" data-action="7">getPreferences()</button>
<button type="button" class="btn btn-outline" data-action="8">reset()</button>
<div class="bg-gray-100 p-4 rounded mb-4 font-mono text-sm" id="api-output">
    API output will appear here...
</div>
/**
 * Programmatic Control - from public/showcase/elements/cookie-consent.
 */
export function mount(root) {
    let basicConsent, customConsent, positionConsent, apiConsent;
      // API example
    function initApiExample() {
        if (!apiConsent) {
          apiConsent = E.cookieConsent({
            message: 'API Example - Control this consent programmatically.',
            position: 'bottom-right',
            layout: 'box',
            privacyPolicyUrl: '#',
            storageKey: 'demo-api-consent',
            autoShow: false,
            reopenSelector: '[data-cookie-consent-open]'
          });
        }
      }
    function apiShow() {
        initApiExample();
        apiConsent.show();
        $(root).find('#api-output').text('Called: show()');
      }
    function apiHide() {
        initApiExample();
        apiConsent.hide();
        $(root).find('#api-output').text('Called: hide()');
      }
    function apiAccept() {
        initApiExample();
        apiConsent.accept();
        $(root).find('#api-output').text('Called: accept()\nState: ' + apiConsent.getState());
      }
    function apiReject() {
        initApiExample();
        apiConsent.reject();
        $(root).find('#api-output').text('Called: reject()\nState: ' + apiConsent.getState());
      }
    function apiCustomize() {
        initApiExample();
        apiConsent.showCustomize();
        $(root).find('#api-output').text('Called: showCustomize()');
      }
    function apiGetState() {
        initApiExample();
        const state = apiConsent.getState();
        $(root).find('#api-output').text('State: ' + state);
      }
    function apiGetPrefs() {
        initApiExample();
        const prefs = apiConsent.getPreferences();
        $(root).find('#api-output').text('Preferences:\n' + JSON.stringify(prefs, null, 2));
      }
    function apiReset() {
        initApiExample();
        apiConsent.reset();
        $(root).find('#api-output').text('Called: reset()\nState: ' + apiConsent.getState());
      }

    // Handlers the old page had inline (onclick=…), wired here.
    $(root).find('[data-action="1"]').on('click', function (event) {
        apiShow();
    });
    $(root).find('[data-action="2"]').on('click', function (event) {
        apiHide();
    });
    $(root).find('[data-action="3"]').on('click', function (event) {
        apiAccept();
    });
    $(root).find('[data-action="4"]').on('click', function (event) {
        apiReject();
    });
    $(root).find('[data-action="5"]').on('click', function (event) {
        apiCustomize();
    });
    $(root).find('[data-action="6"]').on('click', function (event) {
        apiGetState();
    });
    $(root).find('[data-action="7"]').on('click', function (event) {
        apiGetPrefs();
    });
    $(root).find('[data-action="8"]').on('click', function (event) {
        apiReset();
    });
}
// API Methods
const consent = Domma.elements.cookieConsent(options);

consent.show();              // Show consent UI
consent.hide();              // Hide consent UI
consent.accept();            // Accept all cookies
consent.reject();            // Reject non-essential cookies
consent.showCustomize();     // Open preferences modal
consent.getState();          // Get current state
consent.getPreferences();    // Get cookie preferences
consent.isAccepted('analytics'); // Check specific category
consent.reset();             // Clear saved preferences
consent.destroy();           // Remove component

Reopen Trigger

User-Initiated Preference Management

Allow users to reopen cookie preferences after initial consent.

User-Initiated Preference Management
<p>Click here to <a href="#" data-cookie-consent-open="" class="text-primary">manage cookie preferences</a></p>
/**
 * User-Initiated Preference Management - from public/showcase/elements/cookie-consent.
 */
export function mount(root) {
    let basicConsent, customConsent, positionConsent, apiConsent;
      // API example
    function initApiExample() {
        if (!apiConsent) {
          apiConsent = E.cookieConsent({
            message: 'API Example - Control this consent programmatically.',
            position: 'bottom-right',
            layout: 'box',
            privacyPolicyUrl: '#',
            storageKey: 'demo-api-consent',
            autoShow: false,
            reopenSelector: '[data-cookie-consent-open]'
          });
        }
      }
      // Initialize API example for reopen trigger
    initApiExample();
}
// Reopen trigger
Domma.elements.cookieConsent({
    reopenSelector: '[data-cookie-consent-open]',
    // ... other options
});

// In HTML:
<a href="#" data-cookie-consent-open>Cookie Settings</a>

CSS Customisation

Override these CSS variables to customise Cookie Consent appearance and match your design system.

Variable Default Controls
--dm-primary var(--dm-blue-600) Accept button colour
--dm-surface var(--dm-white) Banner background
--dm-border var(--dm-slate-300) Banner border
--dm-shadow-lg 0 10px 15px... Banner shadow

Example Override

:root {
    /* Dark cookie banner */
    --dm-surface: #1e293b;
    --dm-text: #f1f5f9;
}

Full CSS Customisation Cheat-Sheet →