Skip to content

Instantly share code, notes, and snippets.

@ldenoue
Last active August 2, 2025 17:47
Show Gist options
  • Select an option

  • Save ldenoue/27831c77347b698a12621477beb6f36b to your computer and use it in GitHub Desktop.

Select an option

Save ldenoue/27831c77347b698a12621477beb6f36b to your computer and use it in GitHub Desktop.
CookieConsent using Shadcn-vue
<script setup lang="ts">
import { ref, onMounted, watch, computed } from 'vue'
import { Button } from '@/components/ui/button'
// Default prop values
const props = defineProps({
variant: { default: 'default' },
demo: { default: false },
description: {
default:
'We use cookies to ensure you get the best experience on our website. For more information on how we use cookies, please see our cookie policy.',
},
learnMoreHref: { default: '#' },
onAcceptCallback: { default: () => {} },
onDeclineCallback: { default: () => {} },
})
// States
const isOpen = ref(false)
const hide = ref(false)
// Methods
const handleAccept = () => {
isOpen.value = false
document.cookie = 'cookieConsent=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'
setTimeout(() => (hide.value = true), 700)
//props.onAcceptCallback?.()
}
const handleDecline = () => {
isOpen.value = false
setTimeout(() => (hide.value = true), 700)
//props.onDeclineCallback?.()
}
onMounted(() => {
try {
isOpen.value = true
if (document.cookie.includes('cookieConsent=true') && !props.demo) {
isOpen.value = false
setTimeout(() => (hide.value = true), 700)
}
} catch (error) {
console.warn('Cookie consent error:', error)
}
})
const wrapperClasses = computed(() =>
[
'fixed z-50 transition-all duration-700',
isOpen.value ? 'translate-y-0 opacity-100' : 'translate-y-full opacity-0',
props.variant === 'mini'
? 'left-0 right-0 sm:left-4 bottom-4 w-full sm:max-w-3xl'
: 'bottom-0 left-0 right-0 sm:left-4 sm:bottom-4 w-full sm:max-w-md',
].join(' ')
)
</script>
<template>
<div v-if="!hide" :class="wrapperClasses">
<div class="m-3 shadow-lg bg-muted border rounded-lg">
<template v-if="variant === 'default'">
<div class="flex justify-between items-center p-4 pb-2">
<h2 class="text-lg font-semibold">We use cookies</h2>
<Cookie class="h-5 w-5" />
</div>
<div class="px-4 pb-4 space-y-2 text-sm">
<p>{{ description }}</p>
<p class="text-xs text-muted-foreground">
By clicking <span class="font-medium">"Accept"</span>, you agree to our use of cookies.
</p>
<a
:href="learnMoreHref"
class="text-xs text-blue-600 underline underline-offset-4 hover:no-underline"
>
Learn more
</a>
</div>
<div class="flex gap-2 p-4 pt-0">
<Button @click="handleDecline">Decline</Button>
<Button @click="handleAccept">Accept</Button>
</div>
</template>
<template v-else-if="variant === 'small'">
<div class="flex justify-between items-center px-4 pt-4 pb-2">
<h2 class="text-base font-medium">We use cookies</h2>
<Cookie class="h-4 w-4" />
</div>
<div class="px-4 pb-2 text-sm">{{ description }}</div>
<div class="flex gap-2 px-4 pb-4">
<Button @click="handleDecline">Decline</button>
<Button @click="handleAccept">Accept</button>
</div>
</template>
<template v-else-if="variant === 'mini'">
<div class="grid sm:flex gap-4 px-3.5 py-3">
<p class="text-xs sm:text-sm flex-1">{{ description }}</p>
<div class="flex justify-end items-center gap-2 sm:gap-3">
<Button @click="handleDecline">
Decline <span class="sr-only sm:hidden">Decline</span>
</Button>
<Button @click="handleAccept">
Accept <span class="sr-only sm:hidden">Accept</span>
</Button>
</div>
</div>
</template>
</div>
</div>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment