Cookie Conset

@use 'sprucecss/scss/spruce' as *;

.cookie-consent-helper {
  display: flex;
  inset: auto spacer('m') spacer('m');
  justify-content: center;
  pointer-events: none;
  position: fixed;
  z-index: 25;
}

.cookie-consent {
  @include set-css-variable((
    --base-color-text: hsl(0deg 0% 97%),
    --base-color-link: hsl(261deg 54% 70%),
    --base-color-link-hover: hsl(261deg 54% 80%),
  ));

  align-items: center;
  background-color: hsl(260deg 70% 6%);
  border-radius: config('border-radius-lg', $display);
  box-shadow: 0 0 3rem hsl(0deg 0% 0% / 10%);
  color: color('text');
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: spacer('s') spacer('m');
  justify-content: center;
  padding: spacer('s');
  pointer-events: all;
  text-align: center;
  transform: translateY(200%);

  &--slidein {
    animation: slidein config('duration', $transition) forwards;
  }

  &--slideout {
    animation: slideout config('duration', $transition) forwards;
  }

  &__caption {
    @include layout-stack('xs');
  }

  &__btns {
    display: flex;
    gap: spacer('s');
  }
}

@keyframes slidein {
  from {
    transform: translateY(200%);
  }

  to {
    transform: translateY(0);
  }
}

@keyframes slideout {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(200%);
  }
}
<button class="btn btn--outline-primary" data-action="cookie" data-type="analytics" data-on-text="Decline" data-off-text="Accept">analytics cookies</button>
import Cookie from '../../../../js/qkie.js';

(() => {
  const cookie = new Cookie('demo-gdpr-');
  const btns = document.querySelectorAll('button[data-action="cookie"]');
  let caption = '';
  let consentModal = null;
  let redirect = false;

  if (
    !cookie.isset(`analytics`) &&
    !cookie.isset(`denied`)
  ) {
    caption = `<div class="cookie-consent-helper"><div class="cookie-consent cookie-consent--slidein" tabindex="-1">
        <div class="cookie-consent__caption">This is a preview of the cookie consent component. Read more in the <a href="#">privacy policy</a> page.</div>
        <div class="cookie-consent__btns">
        <button class="btn btn--sm btn--decline" data-action="cookie-decline">Decline</button>
          <button class="btn btn--sm btn--primary" data-action="cookie-accept">Accept</button>
        </div>
      </div></div>`;

    document.body.insertAdjacentHTML('afterbegin', caption);
    consentModal = document.querySelector('.cookie-consent');
    consentModal.focus();
  }

  function animationEndCallback () {
    consentModal.removeEventListener('animationend', animationEndCallback);

    if (redirect) {
      window.location.reload();
    }
  }

  document.addEventListener('click', (e) => {
    if (
      e.target &&
      e.target.getAttribute('data-action') === 'cookie-accept'
    ) {
      cookie.set(`analytics`, 'accepted', 365);

      redirect = true;
      consentModal.classList.add('cookie-consent--slideout');
      consentModal.addEventListener('animationend', animationEndCallback);
    }

    if (
      e.target &&
      e.target.getAttribute('data-action') === 'cookie-decline'
    ) {
      cookie.set(`denied`, 'true');

      redirect = false;
      consentModal.classList.add('cookie-consent--slideout');
      consentModal.addEventListener('animationend', animationEndCallback);
    }
  });

  btns.forEach((btn) => {
    if (
      cookie.isset(`${btn.getAttribute('data-type')}`) &&
      cookie.get(`${btn.getAttribute('data-type')}`) === 'accepted'
    ) {
      btn.innerHTML = `${btn.getAttribute('data-on-text')} ${btn.innerHTML}`;
    } else {
      btn.innerHTML = `${btn.getAttribute('data-off-text')} ${btn.innerHTML}`;
    }

    btn.addEventListener('click', () => {
      if (
        cookie.isset(`${btn.getAttribute('data-type')}`) &&
        cookie.get(`${btn.getAttribute('data-type')}`) === 'accepted'
      ) {
        cookie.remove(`${btn.getAttribute('data-type')}`);
      } else {
        cookie.set(`${btn.getAttribute('data-type')}`, 'accepted', 365);
      }
      window.location.reload();
    });
  });
})();

Cookie Conset

This component is one of the most basic implementations of the cookie consent banner.

How It Works

The script differentiates two types of action at the consent banner:

  • accept all types of cookies,
  • decline them.

We place a session cookie when you decline them and ask for permission (again) next time.

If you accept them, we place the category cookie(s). In this case, demo-gdpr-analytics. We use this cookie to identify if we should load analytics-related cookies (like Google Analytics). You can set up any category.

To load your tracking codes, use the following snippet:

if (
  Cookie.isset('demo-gdpr-analytics')
  && Cookie.get('demo-gdpr-analytics') === 'accepted'
) {
  console.log('ANALYTICS');
}

Technical Details

  • As you see in the example, we also included an opt-out button; this is just a button to turn on or off any cookie type. You usually want to place it on your privacy policy page.
  • We handle everything from JS because, in some cases, the back-end cache can kill the cookies.
  • We reload the page after an opt-in or opt-out action because this is the simplest way to load (or turn off) the related scripts.
  • We insert the consent banner right after the opening body and set a focus on it.

Dependencies

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our extensive UI library built with Spruce CSS.

Blog

Read about front-end development and concepts of Spruce CSS.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.