Skip to content

MagicCookie

MagicCookie is a flexible collection of components intended to build cookie banners.

View source View as Markdown

DefaultDemo.vue
<template>
  <magic-cookie-provider
    id="magic-cookie-demo"
    class="bg-surface-base rounded-surface-md flex max-w-xl flex-col p-8"
  >
    <div class="type-surface-body-md text-surface">
      Vue Equipment does not use cookies to provide you a personalized
      experience based on your activity, but for good measure here is a cookie
      banner anyways.
    </div>
    <magic-cookie-view>
      <div class="flex flex-col gap-6 pt-6">
        <magic-cookie-demo-item
          v-for="cookie in cookies"
          :id="cookie.id"
          :key="cookie.id"
          v-slot="{ item }"
          :optional="cookie.optional"
          class="flex flex-col gap-1"
        >
          <m-checkbox
            v-model="item.active"
            :disabled="cookie.optional === false"
            :label="cookie.title"
          />
          <div class="type-surface-caption text-surface-muted pl-8">
            {{ cookie.text }}
          </div>
        </magic-cookie-demo-item>
      </div>
    </magic-cookie-view>
    <div class="flex flex-wrap gap-x-4 gap-y-2 pt-6 sm:flex-nowrap">
      <template v-if="viewActive">
        <m-button mode="plain" block @click="toggleView">Close</m-button>
        <m-button mode="subtle" block @click="onSave">Save</m-button>
      </template>
      <template v-else>
        <m-button mode="plain" block @click="onRejectAll">
          Reject All
        </m-button>
        <m-button mode="subtle" block @click="toggleView"> Settings </m-button>
      </template>
      <m-button block @click="onAcceptAll">Accept All</m-button>
    </div>
  </magic-cookie-provider>
</template>

<script lang="ts" setup>
import { onBeforeUnmount, ref } from 'vue'
import { MButton, MCheckbox } from 'mirror-compat'
import { useMagicEmitter } from '@maas/vue-equipment/plugins/MagicEmitter'
import { useMagicCookie } from '../src/composables/useMagicCookie'
import MagicCookieDemoItem from './MagicCookieDemoItem.vue'

import type { MagicEmitterEvents } from '@maas/vue-equipment/plugins/MagicEmitter'

import type { MagicCookieCallbackArgs } from '../src/types'

const {
  toggleView,
  hideView,
  acceptAll,
  rejectAll,
  acceptSelected,
  onAccept,
  onAcceptSelected,
  onReject,
} = useMagicCookie('magic-cookie-demo')

const cookies = [
  {
    id: 'neccessary',
    optional: false,
    title: 'Strictly Necessary Cookies',
    text: 'These cookies are necessary for the website to function and cannot be switched off in our systems. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms. You can set your browser to block or alert you about these cookies, but some parts of the site will not then work. These cookies do not store any personally identifiable information.',
    maxAge: 24 * 60 * 60 * 60 * 10,
  },
  {
    id: 'performance',
    title: 'Performance Cookies',
    text: 'These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. All information these cookies collect is aggregated and therefore anonymous. If you do not allow these cookies we will not know when you have visited our site, and will not be able to monitor its performance.',
  },
  {
    id: 'functional',
    title: 'Functional Cookies',
    text: 'These cookies enable the website to provide enhanced functionality and personalisation. They may be set by us or by third party providers whose services we have added to our pages. If you do not allow these cookies then some or all of these services may not function properly.',
  },
]

function onRejectAll() {
  rejectAll()
  hideView()
}

function onAcceptAll() {
  acceptAll()
  hideView()
}

function onSave() {
  acceptSelected()
  hideView()
}

function onAcceptCallback(args: MagicCookieCallbackArgs) {
  console.log('ACCEPT:', args)

  switch (true) {
    case args.statistics:
      console.log('Statistics cookies enabled')
      break
    case args.marketing:
      console.log('Marketing cookies enabled')
      break
    case args.preferences:
      console.log('Preferences cookies enabled')
      break
  }
}

function onAcceptSelectedCallback(args: MagicCookieCallbackArgs) {
  console.log('ACCEPT SELECTED:', args)

  switch (args.statistics) {
    case true:
      console.log('Statistics cookies enabled')
      break
    case false:
      console.log('Statistics cookies disabled!')
      break
  }

  switch (args.marketing) {
    case true:
      console.log('Marketing cookies enabled')
      break
    case false:
      console.log('Marketing cookies disabled!')
      break
  }

  switch (args.preferences) {
    case true:
      console.log('Preferences cookies enabled')
      break
    case false:
      console.log('Preferences cookies disabled!')
      break
  }
}

function onRejectCallback(args: MagicCookieCallbackArgs) {
  console.log('REJECT:', args)

  switch (false) {
    case args.statistics:
      console.log('Statistics cookies disabled!')
      break
    case args.marketing:
      console.log('Marketing cookies disabled!')
      break
    case args.preferences:
      console.log('Preferences cookies disabled!')
      break
  }
}

onAccept(onAcceptCallback)
onAcceptSelected(onAcceptSelectedCallback)
onReject(onRejectCallback)

// Handle button state
const emitter = useMagicEmitter()
const viewActive = ref(false)

function afterEnterCallback(payload: MagicEmitterEvents['afterEnter']) {
  if (payload === 'magic-cookie-demo') {
    viewActive.value = true
  }
}

function afterLeaveCallback(payload: MagicEmitterEvents['afterLeave']) {
  if (payload === 'magic-cookie-demo') {
    viewActive.value = false
  }
}

emitter.on('afterEnter', afterEnterCallback)
emitter.on('afterLeave', afterLeaveCallback)

onBeforeUnmount(() => {
  emitter.off('afterEnter', afterEnterCallback)
  emitter.off('afterLeave', afterLeaveCallback)
})
</script>

Anatomy

<template>
  <magic-cookie-provider id="your-cookie-id">
    <magic-cookie-view>
      <magic-cookie-item v-slot="{ item }">
        <!-- your content -->
      </magic-cookie-item>
    </magic-cookie-view>
    <!-- your content -->
  </magic-cookie-provider>
</template>

<script setup>
const { acceptAll } = useMagicCookie('your-cookie-id')
</script>

Installation

CLI

Add @maas/vue-equipment to your dependencies.

pnpm add @maas/vue-equipment

Vue

If you are using Vue, import and add MagicCookiePlugin to your app.

import { createApp } from 'vue'
import { MagicCookiePlugin } from '@maas/vue-equipment/plugins/MagicCookie'

const app = createApp({})

app.use(MagicCookiePlugin)

Nuxt

The cookie banner is available as a Nuxt module. In your Nuxt config file add @maas/vue-equipment/nuxt to your modules and add MagicCookie to the plugins in your configuration.

export default defineNuxtConfig({
  modules: ['@maas/vue-equipment/nuxt'],
  vueEquipment: {
    plugins: ['MagicCookie'],
  },
})

Composable

In order to interact with the cookie banner from anywhere within your app, we provide a useMagicCookie composable. Import it directly when needed.

import { useMagicCookie } from '@maas/vue-equipment/plugins/MagicCookie'

const { acceptAll } = useMagicCookie('your-cookie-id')

function handleClick() {
  acceptAll()
}

Peer Dependencies

MagicCookie relies on the following optional peer dependencies in addition to the core peer dependencies. Package managers don’t install optional peer dependencies automatically, so add them to your project.

Installation

pnpm add @maas/vue-autosize @vueuse/integrations universal-cookie

API Reference

MagicCookieProvider

The MagicCookieProvider wraps the cookie banner and configures all child components according to the provided options.

Props

PropTypeRequired
id
MaybeRef<string>true
options
MagicCookieOptionsfalse

Options

OptionTypeDefault
maxAge
number86400
transition
stringmagic-cookie-view
animation.duration
number300
animation.easing
function
easeOutQuad

MagicCookieItem

The item registers and set the cookie with the given props.

Props

PropTypeRequired
id
MaybeRef<string>true
maxAge
number–

Errors

SourceError CodeMessage
MagicCookieItemmissing_instance_idMagicCookieItem must be nested inside MagicCookieProvider
MagicCookieViewmissing_instance_idMagicCookieView must be used within a MagicCookieProvider