Categories: CSSScriptWeb Design

GDPR Cookie Banner With Category Consent API – Neiki’s Cookie Banner

Neiki’s Cookie Banner is a vanilla JavaScript library that adds an accessible, GDPR-compliant cookie consent banner to static HTML pages, WordPress themes, Laravel apps, and client-side framework projects.

It also stores versioned consent records in localStorage, re-prompts users after a consent version change, and keeps third-party scripts blocked until the visitor accepts the matching category.

Features:

  • 3 banner layouts: bottom/top bar, corner box, and centered modal, each with configurable position options.
  • 3built-in themes: light, dark, and automatic OS-preference detection via prefers-color-scheme.
  • Granular per-category consent toggles with permanent locking for necessary cookies that cannot be disabled.
  • Versioned consent records with ISO timestamps stored in localStorage, with automatic in-memory fallback when storage is unavailable.
  • Script blocking and automatic unlocking.
  • 6 lifecycle callbacks: accept, reject, ready, change, scripts unlock, and consent revocation.
  • Google Consent Mode v2 integration with automatic default-denied push and per-category grant/deny signals.
  • Web Component support for markup-first configuration.
  • Built-in English and Czech translations plus a registration API for custom languages.
  • Full ARIA compliance: dialog roles, focus trap on modal layout, role="switch" toggles with live aria-checked, and prefers-reduced-motion support.
  • Every user-supplied string runs through HTML escaping before DOM injection.
  • Completely free under the MIT license for personal and commercial use.

How to use it:

1. Download and load the neiki-cookie-banner.min.js script in the document.

<script src="dist/neiki-cookie-banner.min.js"></script>

2. If you prefer to manage the stylesheet separately (for preloading or inline overrides), load both files:

<link rel="stylesheet" href="dist/neiki-cookie-banner.css">
<script src="dist/neiki-cookie-banner.js"></script>

3. Create a basic cookie consent banner. Call init() after the script loads and the banner appears on first visit, stores the user’s choice, and stays hidden on return visits.

NeikiCookieBanner.init({
  layout: 'bar', // bar | box | modal
  position: 'bottom', // bottom, top, bottom-left, bottom-right, center
  theme: 'auto', // follows OS preference
  privacyPolicyUrl: '/privacy-policy',
  consentVersion: '1.0' // bump this string to re-prompt all users
});

4. Wrap third-party script (e.g. Google Analytics and Meta Pixel) loading inside onScriptsUnlock so the scripts load only when the user approves the matching category.

NeikiCookieBanner.init({
  layout: 'bar',
  position: 'bottom',
  theme: 'light',
  privacyPolicyUrl: '/privacy',
  consentVersion: '2.0',
  // Fires immediately on accept and on return visits when consent already exists
  onScriptsUnlock: function (categories) {
    // Load GA4 only if the user consented to analytics cookies
    if (categories.analytics) {
      var gaScript = document.createElement('script');
      gaScript.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX';
      gaScript.async = true;
      document.head.appendChild(gaScript);
      window.dataLayer = window.dataLayer || [];
      function gtag() { dataLayer.push(arguments); }
      gtag('js', new Date());
      gtag('config', 'G-XXXXXXXXXX');
    }
    // Load Meta Pixel only if the user consented to marketing cookies
    if (categories.marketing) {
      !function(f,b,e,v,n,t,s) {
        // Standard Meta Pixel initialization snippet
        if (f.fbq) return;
        n=f.fbq=function(){ n.callMethod ? n.callMethod.apply(n,arguments) : n.queue.push(arguments) };
        if (!f._fbq) f._fbq=n;
        n.push=n; n.loaded=!0; n.version='2.0';
        n.queue=[];
        t=b.createElement(e); t.async=!0;
        t.src=v; s=b.getElementsByTagName(e)[0];
        s.parentNode.insertBefore(t,s)
      }(window, document, 'script', 'https://connect.facebook.net/en_US/fbevents.js');
      fbq('init', '000000000000000');
      fbq('track', 'PageView');
    }
  },
  onReject: function () {
    // User rejected all non-necessary cookies; no third-party scripts load
    console.log('User rejected optional cookies.');
  }
});

5. The library supports a declarative approach to script blocking. Add type="text/plain" and data-category to any script tag. The library converts it to a real executable script when the matching category is approved.

<!-- This script stays inert (type="text/plain") until analytics consent is given -->
<script type="text/plain" data-category="analytics" src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX" async></script>

<!-- Inline script with the same pattern -->
<script type="text/plain" data-category="analytics">
  window.dataLayer = window.dataLayer || [];
  function gtag() { dataLayer.push(arguments); }
  gtag('js', new Date());
  gtag('config', 'G-XXXXXXXXXX');
</script>
<script>
  NeikiCookieBanner.init({
    privacyPolicyUrl: '/legal/privacy',
    consentVersion: '1.0'
    // No callback needed; the library auto-unlocks scripts on consent
  });
</script>

6. Custom Categories and Modal Layout:

NeikiCookieBanner.init({

  layout: 'modal',            // Modal shows the preferences panel immediately
  theme: 'dark',
  privacyPolicyUrl: '/privacy',
  consentVersion: '3.0',
  lockScroll: true,           // Prevents scrolling while the banner is open

  categories: {
    necessary: {
      label: 'Required',
      description: 'Core site functions. These cannot be turned off.',
      locked: true            // User cannot toggle this off
    },
    analytics: {
      label: 'Analytics',
      description: 'Helps us understand page performance and traffic sources.',
      enabled: false          // Off by default; user must opt in
    },
    experiments: {
      label: 'A/B Tests',
      description: 'Tracks which feature variants you see during testing.',
      enabled: false
    }
  },

  onScriptsUnlock: function (categories) {
    if (categories.analytics) {
      // Load your analytics script here
    }
    if (categories.experiments) {
      // Initialize your A/B testing framework here
    }
  }
});

7. Prefer HTML configuration over JavaScript? Use the <neiki-cookie-banner> custom element. Place it anywhere in <body> before the closing tag.

<neiki-cookie-banner
  data-layout="modal"
  data-theme="auto"
  data-position="center"
  data-consent-version="1.0"
  data-privacy-policy-url="/privacy"
  data-lock-scroll="true"
  data-close-on-overlay-click="true">
</neiki-cookie-banner>

8. Re-open the Banner from a Footer Link. Add data-neiki-show-prefs to any anchor or button and the library re-opens the banner on click.

<a href="#" data-neiki-show-prefs>Manage Cookie Preferences</a>

9. If your site uses Google Tag Manager with Consent Mode, set googleConsentMode: true. The library pushes default-denied signals immediately on init() (before any GTM tags fire) and updates them when the user makes a choice.

<!-- GTM snippet must load before or alongside the cookie banner -->
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){...})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
NeikiCookieBanner.init({
  privacyPolicyUrl: '/privacy',
  consentVersion: '1.0',
  googleConsentMode: true,    // Pushes gtag('consent','default', ...) immediately
  // No manual gtag() calls needed; the library handles all consent signals
});

10. Override the default banner’s styles with CSS custom properties on the .neiki-cb root selector.

.neiki-cb {
  --neiki-cb-accent: #0f62fe;     /* Primary button background */  --neiki-cb-radius: 8px;         /* Border radius for the container */}

11. All configuration options.

  • layout ('bar' | 'box' | 'modal'): Sets the visual layout. Bar spans the full width, Box appears in a corner, Modal centers with a backdrop.
  • position (string): Positions the banner. Accepts top, bottom, bottom-left, bottom-right, and center.
  • theme ('light' | 'dark' | 'auto'): Sets the color theme. auto reads prefers-color-scheme from the OS.
  • title (string): Overrides the banner heading. Defaults to 'We use cookies'.
  • description (string): Overrides the banner body text. Defaults to built-in copy.
  • privacyPolicyUrl (string): Appends a privacy policy link to the description when set.
  • privacyPolicyText (string): Sets the link text for the privacy policy URL. Defaults to 'Privacy Policy'.
  • acceptAllText (string): Sets the primary button label. Defaults to 'Accept All'.
  • rejectAllText (string): Sets the reject button label. Pass an empty string to hide this button.
  • customizeText (string): Sets the customize/preferences button label. Defaults to 'Customize'.
  • savePreferencesText (string): Sets the label for the save button inside the preferences panel.
  • categories (object): Defines the consent categories. See the Custom Categories example above.
  • showAfterMs (number): Sets the delay in milliseconds before the banner appears on first visit. Defaults to 300.
  • closeOnOverlayClick (boolean): Closes the modal layout when the user clicks the backdrop. Defaults to false.
  • lockScroll (boolean): Adds overflow: hidden to the body while the banner is open. Defaults to false.
  • animationIn ('slide' | 'none'): Sets the entry animation. Defaults to 'slide'.
  • consentVersion (string): A version string stored alongside consent. Bump it to force a re-prompt for all users. Defaults to '1.0'.
  • googleConsentMode (boolean): Activates Google Consent Mode v2 integration. Defaults to false.
  • language (string): Sets the i18n language. Defaults to 'en'. Use 'cs' for Czech or register a custom translation with addTranslation().
  • zIndex (number): Sets the stacking order of the banner element. Defaults to 9999.
  • onAccept (function): Fires when the user accepts all cookies or saves custom preferences.
  • onReject (function): Fires when the user clicks Reject All.
  • onReady (function): Fires on page load when valid stored consent already exists. Receives the stored consent object.
  • onChange (function): Fires on every consent state change.
  • onScriptsUnlock (function): Fires with the approved categories object. Use this to load third-party scripts.
  • onRevoke (function): Fires when revoke() is called programmatically.

12. API methods:

// Initialize the banner and show it if no valid consent is stored
NeikiCookieBanner.init({ layout: 'bar', consentVersion: '1.0' });

// Re-open the banner (re-renders the panel and resets toggle states)
NeikiCookieBanner.show();

// Close the banner programmatically
NeikiCookieBanner.hide();

// Returns the stored consent object or null if no consent has been recorded
// Shape: { version: '1.0', timestamp: '2026-05-01T10:00:00.000Z', categories: { ... } }
const consent = NeikiCookieBanner.getConsent();

// Returns true if any consent record exists (regardless of what was accepted)
const hasConsented = NeikiCookieBanner.hasConsented();

// Returns true if the user approved a specific category
const analyticsAllowed = NeikiCookieBanner.isAllowed('analytics');

// Clears stored consent and re-shows the banner
NeikiCookieBanner.reset();

// Clears stored consent, revokes GCM signals, re-locks unlocked scripts, fires onRevoke,
// and optionally re-opens the banner (pass false to suppress re-open)
NeikiCookieBanner.revoke();         // Re-opens banner
NeikiCookieBanner.revoke(false);    // Revokes consent silently

// Manually unlock blocked scripts for a specific category
NeikiCookieBanner.unlockScripts('analytics');

// Register a custom translation table
NeikiCookieBanner.addTranslation('de', {
  title: 'Wir verwenden Cookies',
  acceptAllText: 'Alle akzeptieren',
  rejectAllText: 'Alle ablehnen',
  // ... rest of the translation keys
});

// Retrieve a registered translation table
const table = NeikiCookieBanner.getTranslation('de');

Alternatives:

FAQs:

Q: The banner re-appears on every page load. What’s wrong?
A: Check your init() call and verify the version string matches what’s in localStorage under the key neiki_cookie_consent.

Q: How do I re-prompt users after a privacy policy update?
A: Bump the consentVersion string in your init() call. The library compares the stored version against the configured one on every page load. A mismatch triggers a full re-prompt. Previous consent records are overwritten on the next user action.

Q: How do I add a translation for a language not included?
A: Call NeikiCookieBanner.addTranslation('fr', { title: '...', acceptAllText: '...', ... }) before calling init(). Then pass language: 'fr' in your init() config. The library falls back to English for any missing key in the custom table.

The post GDPR Cookie Banner With Category Consent API – Neiki’s Cookie Banner appeared first on CSS Script.

rssfeeds-admin

Share
Published by
rssfeeds-admin

Recent Posts

Q1 2026 Ransomware Attacks Hit 2,122 Organizations Worldwide

The ransomware landscape is shifting from a chaotic swarm of minor players into a highly…

1 hour ago

Michigan DNR adds two water-scooping planes ahead of wildfire season

GAYLORD, MI (WOWO) The Michigan Department of Natural Resources has added two water-scooping aircraft to…

1 hour ago

Michigan Economic Development Corporation under pressure following fraud allegations

LANSING, MI (WOWO) Former criminal charges filed against a Michigan Economic Development Corporation board member…

1 hour ago

Windows BitLocker 0-Day Vulnerability Enables Access to Encrypted Drives

Two new unpatched Windows BitLocker zero-day vulnerabilities significantly compromise Microsoft’s ecosystem. The exploits include a…

1 hour ago

Elkhart County crews work to repair damaged gas main after evacuation order

ELKHART COUNTY, IND. (WOWO) A gas leak prompted evacuations Wednesday morning in an Elkhart County…

2 hours ago

This website uses cookies.