@mozmeao/consent-banner

1.0.0 • Public • Published

Consent banner

This NPM package provides code for implementing a lightweight and accessible cookie / data consent banner on Mozilla websites. This banner is used primarily by the Websites Team on sites such as www.mozilla.org, but the code is provided here as a package should other teams at Mozilla find it useful.

What does it do?

The package contains all the CSS/JS required for displaying a banner, the necessary functions for accepting or rejecting cookies, as well as an event based system to help your website code to manage user consent actions. The UI and copy has been reviewed by Mozilla's legal team, and has also undergone internal accessibility review. The banner behavior defaults to opt-in for cookies, however it can also be configured to be opt-out depending on your requirements.

When should this banner be used?

Please see the Mozilla confluence page for an FAQ on how and when a cookie banner should be used on Mozilla websites. You can also ask questions in the #websites-cookie-banner channel on Slack.

What does it not do?

This package does not take on responsibility for deciding if the banner should be displayed depending on a website visitor's geographical location. That part is up to individual sites to decide what is required / appropriate. Mozilla's legal team can help with guidance for individual sites to follow.

Does the banner set a cookie that can be used across Mozilla subdomains?

Mozilla's legal team have stated that it is OK to assume that consent applies across mozilla.org subdomains, as long as the technologies deployed on those subdomains function in the same way (and for the same purposes). As such, the banner sets a consent cookie with a default domain of .mozilla.org when either accepting or rejecting cookies.

It is therefore recommended to talk to legal about how your website uses cookies and other analytics tools first, before using this banner. We should not assume that consent applies across Mozilla websites that are on entirely different domains.

How can visitors change their cookie settings after interacting with the banner?

There will be a cookie settings page hosted on https://www.mozilla.org/ that explains how Mozilla uses cookies and other analytics technologies. The page also enables people to update their cookie settings after interacting with the banner. It is a legal requirement to link to this page in the banner UI, as well as via a "Cookies" link in the website footer so that people can get back to it after the banner has been dismissed.

[!IMPORTANT] Mozilla websites should only link to the hosted cookie settings page above if their website is also hosted on a mozilla.org subdomain, and are using the default consent cookie that can be read across Mozilla subdomains. Mozilla websites on entirely different domains or using different consent cookies should implement their own settings page.

Installation

Install via NPM:

npm install @mozmeao/consent-banner --save

It is also required to install @mozmeao/cookie-helper as a peer dependency.

npm install @mozmeao/cookie-helper --save

Usage

Banner JavaScript

Import the banner via import, require, or by using a global variable in your script tag (choose one of the methods below):

// ES module
import MozConsentBanner from '@mozmeao/consent-banner';

// Common JS
const MozConsentBanner = require('@mozmeao/consent-banner');

// Global variable
const MozConsentBanner = window.MozConsentBanner;

You must also load CookieHelper (which can also be imported using any of the above methods), and pass that as an option to the banner when initializing it:

import CookieHelper from '@mozmeao/cookie-helper';

To initialize the banner:

MozConsentBanner.init({
    helper: CookieHelper,
});

There are also several other optional arguments you can use when initializing the banner. A full list of options are shown below:

Option Required Type Description Default Value
cookieDomain false String Sets a consent cookie for a specific host name .mozilla.org
cookieExpiryDays false Number Consent cookie expiry by number of days. 182 (6 months)
cookieID false String Consent cookie identifier. moz-consent-pref
helper true Object Reference to @mozmeao/cookie-helper peer dependency. null
optOut false Boolean Sets the banner to opt-out mode. false

Opening and closing the banner UI

The consent banner code aims to be UI independent, so it fires custom JavaScript events for when things should happen. For example, when the banner should open a mozConsentOpen event is fired. And when the banner should close it fires a mozConsentClose event. A website can add standard event listeners on the window object for these events.

// Bind open and close events before calling init().
window.addEventListener('mozConsentOpen', openBanner, false);
window.addEventListener('mozConsentClose', closeBanner, false);

MozConsentBanner.init({
    helper: CookieHelper,
});

[!IMPORTANT] The mozConsentOpen event listener should be bound before init() is called, since the event can fire straight away.

The mozConsentOpen event will be fired automatically when init() is called and a consent cookie does not yet exist. Similarly, the mozConsentClose event will be fired when cookies are either accepted or rejected and the banner is no longer needed to remain open.

Here are is a basic vanilla JS example for handling opening and closing the banner:

function openBanner() {
    // Bind click event listeners for banner buttons
    document
        .getElementById('moz-consent-banner-button-accept')
        .addEventListener('click', MozConsentBanner.onAcceptClick, false);
    document
        .getElementById('moz-consent-banner-button-reject')
        .addEventListener('click', MozConsentBanner.onRejectClick, false);

    // Show the banner
    document.getElementById('moz-consent-banner').classList.add('is-visible');
}

function closeBanner() {
    // Unbind click event listeners
    document
        .getElementById('moz-consent-banner-button-accept')
        .removeEventListener('click', MozConsentBanner.onAcceptClick, false);
    document
        .getElementById('moz-consent-banner-button-reject')
        .removeEventListener('click', MozConsentBanner.onRejectClick, false);

    // Hide the banner
    document.getElementById('moz-consent-banner').classList.remove('is-visible');
}

Consent cookie

When either accepting or rejecting cookies, a consent cookie with the following attribute key/value pairs is set.

Attribute Value
id Defaults to moz-consent-pref.
value A stringified JSON object representing a visitor's granular cookie consent settings e.g. { preference: true, analytics: false }. Each key represents the consent status for "preference cookies" and "analytics cookies" respectively.
expiry Defaults to 6 months from the date when the cookie is set.
path Set to / so the cookie is readable from all pages.
domain Defaults to the same domain where the cookie was created. If the website is a mozilla.org subdomain, then the cookie domain will be set to .mozilla.org so that it is readable across all mozilla.org subdomains.
samesite Set to lax.

Listening for consent status in website code

When the accept or reject buttons are clicked, the banner's JavaScript will fire a custom mozConsentStatus event. Your website's code can listen for this event and respond accordingly to determine if analytics scripts should be loaded, or attribution code should be run.

function initAnalytics(e) {
    const hasConsent = e.detail.analytics;

    if (hasConsent) {
        // Load analytics code / scripts here

        window.removeEventListener('mozConsentStatus', initAnalytics, false);
    }
}

window.addEventListener('mozConsentStatus', initAnalytics, false);

[!IMPORTANT] To ensure that your front-end code receives events correctly, it is important to make sure that MozConsentBanner.init() is called after mozConsentStatus event listeners have been bound in your website's code. The easiest way to do this is to make sure the banner JS is the last script loaded in your web page, or to wait for the window load event to fire.

If the banner has been interacted with previously and a consent cookie already exists when init() is called, a mozConsentStatus event will fire instead of a mozConsentOpen event.

Banner HTML

As mentioned earlier, the banner JavaScript code is written in a way that aims to be UI independent. This is because Mozilla websites are often built using different technology stacks for the front-end. Rather than try and take on the role of rendering HTML, it is instead left to the website implementing the banner.

Here's an example of the recommended banner HTML markup:

<aside class="moz-consent-banner" id="moz-consent-banner" role="region" aria-label="Cookie Banner" data-nosnippet="true">
    <div class="moz-consent-banner-content">
        <h2  class="moz-consent-banner-heading">Help us improve your Mozilla experience</h2>
        <div class="moz-consent-banner-copy">
            <p>
                In addition to cookies necessary for this site to function, we’d like your permission to set some additional
                Cookies to better understand your browsing needs and improve your experience. Rest assured - we value your privacy.
            </p>
            <div class="moz-consent-banner-controls">
                <button type="button" id="moz-consent-banner-button-reject" class="moz-consent-banner-button moz-consent-banner-button-reject">
                    Reject All Additional Cookies
                </button>
                <button type="button" id="moz-consent-banner-button-accept" class="moz-consent-banner-button moz-consent-banner-button-accept">
                    Accept All Additional Cookies
                </button>
                <a href="https://www.mozilla.org/privacy/websites/cookie-settings/">
                    Cookie settings
                </a>
            </div>
        </div>
    </div>
</aside>

You can also view the demo file in the GitHub repository to see a working example of the banner HTML.

HTML accessibility guidelines

The default banner CSS styling has undergone internal accessibility review, however there are a couple of important things to note in the banner HTML:

  • The banner should be an <aside> element, with role="region" and aria-label="Cookie Banner" attributes, so that the banner can easily be searched for and discovered by screen reader users.
  • The banner should be the first element that appears in your page's HTML, ideally right after the opening <body>. This helps to ensure that the buttons appear early in keyboard focus order, so users don't have to tab through all of the web page content before reaching the banner.

Banner CSS

You can import the banner Sass styles using:

@import '~@mozmeao/consent-banner/styles';

There's also a pre-compiled CSS file called styles.css in the package root which you can alternatively load:

<link href="/path/to/styles.css" rel="stylesheet" type="text/css">

[!NOTE] The banner CSS defines the Inter web font as a font-family, falling back to san-serif. This package does not include the Inter font directly, so the it must be loaded separately if you wish to use it.

Browser support

The banner is supported in all modern evergreen web browsers. It should also work in legacy browsers as far back as Internet Explorer 9.

Local development

  1. Download this repo: git clone https://github.com/mozmeao/consent-banner.git
  2. Move into repo folder: cd consent-banner
  3. Build the banner files: npm install && npm start
  4. A demo page for local development should automatically open at http://localhost:8000/

Running tests

To perform a run of the front-end JS tests using Jasmine and Jasmine Browser Runner in both Firefox and Chrome:

npm run test

Building the NPM package

We use a Webpack configuration for building the contents of the NPM package ready for publishing. To build the package, run:

npm run build

This will lint files, run tests, and then build the NPM package content in the ./dist/ directory.

Publishing to NPM

These steps assume you have logged into the NPM CLI and are apart of the @mozmeao organization on NPM.

The package is published to NPM under the @mozmeao/consent-bannner namespace/package name. To publish a release to NPM, use the following steps:

  1. Before you start make sure the project's CHANGELOG.md is up to date.
  2. Update the package version number in package.json (use [Semantic Versioning][semver] to determine what the new version number should be).
  3. Run npm install to update the package-lock.json file.
  4. Submit a pull request with your against the main branch. Once the changes have been approved and merged to main:
  5. Run npm run build to run the front-end tests and then build the final package. The package contents will be located in ./dist/.
  6. Tag a new release. You can do this either using Git tag, or directly on the GitHub website. (Example: git tag -a v1.1.0). If you used Git tag, push your tags to the repo using git push --tags
  7. If the build is successful and all tests pass, publish to NPM using npm publish ./dist/.

Package Sidebar

Install

npm i @mozmeao/consent-banner

Weekly Downloads

197

Version

1.0.0

License

MPL-2.0

Unpacked Size

54.9 kB

Total Files

7

Last publish

Collaborators

  • maureenlholland
  • agibsonmoz
  • reemhamoui
  • stevejalim-mozilla
  • nathanbarrett24