Consenti

Vue 3 + Pinia — Composable-Driven Integration

A frontend-only Vue 3 app where several unrelated components need to know whether analytics is granted. Rather than calling useConsent()in every one of them, it's wrapped once in a Pinia store — Pinia's setup-store syntax can call composables directly, so this is a thin wrapper, not a reimplementation.

What this demonstrates

  • Registering the widget once with setConsentiWidget()
  • A Pinia setup store built directly on top of useConsent()
  • A derived, memoized getter (analyticsEnabled) any component can read

1. Create and register the widget

main.ts
ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { ConsentiSetup } from '@consenti/ui'
import { setConsentiWidget } from '@consenti/ui/vue'
import App from './App.vue'

const widget = new ConsentiSetup({ compliance: { type: 'opt-in' } })
setConsentiWidget(widget)

createApp(App).use(createPinia()).mount('#app')
ℹ️Using Nuxt 3? Do this inside a .client.ts plugin instead of main.ts — see @consenti/ui/vue in the Frameworks reference.

2. Wrap useConsent() in a Pinia store

stores/consent.ts
ts
import { computed } from 'vue'
import { defineStore } from 'pinia'
import { useConsent } from '@consenti/ui/vue'

export const useConsentStore = defineStore('consent', () => {
  const { hasConsent, consent, isCookieGranted, showModal, grantAll, denyAll } = useConsent()

  const analyticsEnabled = computed(() => isCookieGranted('analytics'))
  const marketingEnabled = computed(() => isCookieGranted('marketing'))

  return { hasConsent, consent, analyticsEnabled, marketingEnabled, showModal, grantAll, denyAll }
})

hasConsent, consent, bannerVisible, and modalVisible from useConsent() are Vue Refs — Pinia auto-unwraps them at the store boundary, so components read them without .value.

3. Use it anywhere

components/AnalyticsGate.vue
vue
<script setup lang="ts">
import { useConsentStore } from '@/stores/consent'
const consent = useConsentStore()
</script>

<template>
  <button v-if="!consent.analyticsEnabled" @click="consent.showModal()">
    Enable Analytics
  </button>
  <span v-else class="text-sm text-slate-400">Analytics enabled</span>
</template>