CookieConsent
Reusable cookie consent component.
Usage
Components are auto-discovered. Use the component directly in any .wrn view:
<CookieConsent />Legacy mount name: data-component="CookieConsent".
Props and attributes
| Prop | Type | Requirement | Default |
|---|---|---|---|
class | string | Optional | "" |
Slots
This component does not declare a slot.
Events
clickchange
Source contract
Installed source: components/CookieConsent.wrn
component CookieConsent {
props {
class: string = ""
}
state bannerOpen = false
state preferencesOpen = false
state analyticsCookies = false
state personalizationCookies = false
state marketingCookies = false
view {
<div class="{class}" class:hidden="!bannerOpen">
<!-- Cookie consent banner -->
<section
role="dialog"
aria-modal="false"
aria-labelledby="cookie-consent-title"
aria-describedby="cookie-consent-description"
class="fixed inset-x-0 bottom-0 z-[80] p-4 sm:p-5 lg:p-6 {class}"
class:hidden="!bannerOpen || preferencesOpen"
class:block="bannerOpen && !preferencesOpen"
>
<div
class="mx-auto w-full max-w-7xl overflow-hidden rounded-3xl border border-slate-200 bg-white/95 shadow-2xl shadow-slate-950/20 backdrop-blur-xl dark:border-white/10 dark:bg-slate-900/95 dark:shadow-black/40"
>
<div class="grid items-center gap-6 p-5 sm:p-6 lg:grid-cols-[minmax(0,1fr)_auto] lg:p-7">
<!-- Message -->
<div class="flex items-start gap-4">
<span
class="grid h-11 w-11 shrink-0 place-items-center rounded-2xl bg-indigo-100 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300"
>
<span class="icon-[lucide--cookie] h-5 w-5" aria-hidden="true" >
</span>
</span>
<div class="min-w-0">
<div class="flex flex-wrap items-center gap-2">
<h2
id="cookie-consent-title"
class="text-base font-bold text-slate-950 dark:text-white"
>
Your privacy matters
</h2>
<span
class="inline-flex items-center rounded-full bg-emerald-100 px-2.5 py-1 text-[10px] font-bold uppercase tracking-wide text-emerald-700 dark:bg-emerald-500/15 dark:text-emerald-300"
>
Privacy first
</span>
</div>
<p
id="cookie-consent-description"
class="mt-2 max-w-3xl text-sm leading-6 text-slate-600 dark:text-slate-400"
>
We use essential cookies to operate WRNexusJS. With your
permission, we also use analytics and personalization cookies
to improve your experience.
</p>
<div class="mt-3 flex flex-wrap items-center gap-x-4 gap-y-2">
<a
href="/cookies"
class="inline-flex items-center gap-1.5 text-xs font-semibold text-indigo-600 transition hover:text-indigo-800 dark:text-indigo-400 dark:hover:text-indigo-300"
>
Cookie policy
<span class="icon-[lucide--arrow-up-right] h-3.5 w-3.5" aria-hidden="true" >
</span>
</a>
<a
href="/privacy"
class="inline-flex items-center gap-1.5 text-xs font-semibold text-slate-500 transition hover:text-indigo-700 dark:text-slate-400 dark:hover:text-indigo-300"
>
Privacy policy
</a>
</div>
</div>
</div>
<!-- Actions -->
<div class="grid gap-2 sm:grid-cols-3 lg:flex lg:items-center">
<button
type="button"
@click=" analyticsCookies = false; personalizationCookies = false; marketingCookies = false; bannerOpen = false "
data-cookie-action="essential"
class="inline-flex h-11 items-center justify-center rounded-xl border border-slate-200 bg-white px-4 text-sm font-semibold text-slate-700 transition hover:border-slate-300 hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-200 dark:hover:border-white/20 dark:hover:bg-white/10 dark:hover:text-white"
>
Essential only
</button>
<button
type="button"
@click="preferencesOpen = true"
class="inline-flex h-11 items-center justify-center gap-2 rounded-xl border border-indigo-200 bg-indigo-50 px-4 text-sm font-semibold text-indigo-700 transition hover:border-indigo-300 hover:bg-indigo-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-indigo-500/20 dark:bg-indigo-500/10 dark:text-indigo-300 dark:hover:border-indigo-500/30 dark:hover:bg-indigo-500/15"
>
<span class="icon-[lucide--settings-2] h-4 w-4" aria-hidden="true" >
</span>
Preferences
</button>
<button
type="button"
@click=" analyticsCookies = true; personalizationCookies = true; marketingCookies = true; bannerOpen = false "
data-cookie-action="accept-all"
class="inline-flex h-11 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-5 text-sm font-bold text-white shadow-lg shadow-indigo-600/20 transition hover:-translate-y-0.5 hover:bg-indigo-500 hover:shadow-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-900"
>
Accept all
<span class="icon-[lucide--check] h-4 w-4" aria-hidden="true" >
</span>
</button>
</div>
</div>
</div>
</section>
<!-- Preferences backdrop -->
<button type="button" @click="preferencesOpen = false" aria-label="Close cookie preferences" class="fixed inset-0 z-[90] bg-slate-950/50 backdrop-blur-sm" class:hidden="!preferencesOpen" class:block="preferencesOpen" >
</button>
<!-- Preferences modal -->
<section
role="dialog"
aria-modal="true"
aria-labelledby="cookie-preferences-title"
aria-describedby="cookie-preferences-description"
class="fixed inset-0 z-[100] overflow-y-auto p-4 sm:p-6"
class:hidden="!preferencesOpen"
class:block="preferencesOpen"
>
<div class="flex min-h-full items-end justify-center sm:items-center">
<div
class="relative w-full max-w-2xl overflow-hidden rounded-t-3xl border border-slate-200 bg-white shadow-2xl shadow-slate-950/30 dark:border-white/10 dark:bg-slate-900 dark:shadow-black/50 sm:rounded-3xl"
>
<!-- Modal header -->
<header class="border-b border-slate-200 px-5 py-5 dark:border-white/10 sm:px-6">
<div class="flex items-start justify-between gap-4">
<div class="flex items-start gap-4">
<span
class="grid h-11 w-11 shrink-0 place-items-center rounded-2xl bg-indigo-100 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300"
>
<span class="icon-[lucide--sliders-horizontal] h-5 w-5" aria-hidden="true" >
</span>
</span>
<div>
<h2
id="cookie-preferences-title"
class="text-lg font-bold tracking-tight text-slate-950 dark:text-white"
>
Cookie preferences
</h2>
<p
id="cookie-preferences-description"
class="mt-1 text-sm leading-6 text-slate-500 dark:text-slate-400"
>
Choose which optional cookies WRNexusJS may use.
</p>
</div>
</div>
<button
type="button"
@click="preferencesOpen = false"
aria-label="Close cookie preferences"
class="grid h-10 w-10 shrink-0 place-items-center rounded-xl border border-slate-200 bg-white text-slate-500 transition hover:bg-slate-100 hover:text-slate-950 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:border-white/10 dark:bg-white/5 dark:text-slate-400 dark:hover:bg-white/10 dark:hover:text-white"
>
<span class="icon-[lucide--x] h-4.5 w-4.5" aria-hidden="true" >
</span>
</button>
</div>
</header>
<!-- Preference groups -->
<div class="max-h-[60dvh] space-y-3 overflow-y-auto p-5 sm:p-6">
<!-- Essential -->
<article
class="rounded-2xl bg-emerald-500/10 p-4 ring-1 ring-inset ring-emerald-500/15 transition dark:bg-emerald-500/10 dark:ring-emerald-400/10"
>
<div class="flex items-start justify-between gap-4">
<div class="flex items-start gap-3">
<span
class="grid h-10 w-10 shrink-0 place-items-center rounded-xl bg-emerald-500/15 text-emerald-700 dark:bg-emerald-400/10 dark:text-emerald-300"
>
<span class="icon-[lucide--shield-check] h-4.5 w-4.5" aria-hidden="true" >
</span>
</span>
<div>
<div class="flex flex-wrap items-center gap-2">
<h3 class="text-sm font-bold text-slate-950 dark:text-white">
Essential cookies
</h3>
<span
class="rounded-full bg-emerald-500/15 px-2 py-0.5 text-[10px] font-bold uppercase tracking-wide text-emerald-700 dark:bg-emerald-400/10 dark:text-emerald-300"
>
Always active
</span>
</div>
<p class="mt-1.5 text-xs leading-5 text-slate-600 dark:text-slate-400">
Required for authentication, security, sessions, preferences, and core website functionality.
</p>
</div>
</div>
<span
class="relative inline-flex h-6 w-11 shrink-0 cursor-not-allowed rounded-full bg-emerald-500"
aria-hidden="true"
>
<span class="absolute right-1 top-1 h-4 w-4 rounded-full bg-white shadow-sm" >
</span>
</span>
</div>
</article>
<!-- Analytics -->
<article
class="rounded-2xl p-4 transition-all duration-200 {analyticsCookies ? 'bg-indigo-50 ring-1 ring-inset ring-indigo-200 dark:bg-indigo-500/10 dark:ring-indigo-500/20' : 'bg-slate-50 ring-1 ring-inset ring-slate-200 dark:bg-white/5 dark:ring-white/10' }"
>
<label class="flex cursor-pointer items-start justify-between gap-4">
<span class="flex min-w-0 items-start gap-3">
<span
class="grid h-10 w-10 shrink-0 place-items-center rounded-xl transition-all duration-200 {analyticsCookies ? 'bg-indigo-100 text-indigo-700 dark:bg-indigo-500/15 dark:text-indigo-300' : 'bg-slate-200 text-slate-500 dark:bg-white/10 dark:text-slate-400' }"
>
<span class="icon-[lucide--chart-no-axes-combined] h-5 w-5" aria-hidden="true" >
</span>
</span>
<span class="min-w-0">
<span class="block text-sm font-bold text-slate-950 dark:text-white">
Analytics cookies
</span>
<span class="mt-1 block text-xs leading-5 text-slate-600 dark:text-slate-400">
Help us understand website usage, performance, and navigation patterns.
</span>
</span>
</span>
<span class="relative mt-0.5 shrink-0">
<input
type="checkbox"
name="analytics"
checked="{analyticsCookies}"
@change="analyticsCookies = event.target.checked"
class="peer sr-only"
/>
<span class="block h-6 w-11 rounded-full bg-slate-300 transition-colors duration-200 peer-checked:bg-indigo-600 peer-focus-visible:ring-4 peer-focus-visible:ring-indigo-500/20 dark:bg-slate-700" >
</span>
<span class="absolute left-1 top-1 h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200 peer-checked:translate-x-5" >
</span>
</span>
</label>
</article>
<!-- Personalization -->
<article
class="rounded-2xl p-4 transition-all duration-200 {personalizationCookies ? 'bg-violet-50 ring-1 ring-inset ring-violet-200 dark:bg-violet-500/10 dark:ring-violet-500/20' : 'bg-slate-50 ring-1 ring-inset ring-slate-200 dark:bg-white/5 dark:ring-white/10' }"
>
<label class="flex cursor-pointer items-start justify-between gap-4">
<span class="flex min-w-0 items-start gap-3">
<span
class="grid h-10 w-10 shrink-0 place-items-center rounded-xl transition-all duration-200 {personalizationCookies ? 'bg-violet-100 text-violet-700 dark:bg-violet-500/15 dark:text-violet-300' : 'bg-slate-200 text-slate-500 dark:bg-white/10 dark:text-slate-400' }"
>
<span class="icon-[lucide--sparkles] h-5 w-5" aria-hidden="true" >
</span>
</span>
<span class="min-w-0">
<span class="block text-sm font-bold text-slate-950 dark:text-white">
Personalization cookies
</span>
<span class="mt-1 block text-xs leading-5 text-slate-600 dark:text-slate-400">
Remember your choices and provide a more relevant website experience.
</span>
</span>
</span>
<span class="relative mt-0.5 shrink-0">
<input
type="checkbox"
name="personalization"
checked="{personalizationCookies}"
@change="personalizationCookies = event.target.checked"
class="peer sr-only"
/>
<span class="block h-6 w-11 rounded-full bg-slate-300 transition-colors duration-200 peer-checked:bg-violet-600 peer-focus-visible:ring-4 peer-focus-visible:ring-violet-500/20 dark:bg-slate-700" >
</span>
<span class="absolute left-1 top-1 h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200 peer-checked:translate-x-5" >
</span>
</span>
</label>
</article>
<!-- Marketing -->
<article
class="rounded-2xl p-4 transition-all duration-200 {marketingCookies ? 'bg-rose-50 ring-1 ring-inset ring-rose-200 dark:bg-rose-500/10 dark:ring-rose-500/20' : 'bg-slate-50 ring-1 ring-inset ring-slate-200 dark:bg-white/5 dark:ring-white/10' }"
>
<label class="flex cursor-pointer items-start justify-between gap-4">
<span class="flex min-w-0 items-start gap-3">
<span
class="grid h-10 w-10 shrink-0 place-items-center rounded-xl transition-all duration-200 {marketingCookies ? 'bg-rose-100 text-rose-700 dark:bg-rose-500/15 dark:text-rose-300' : 'bg-slate-200 text-slate-500 dark:bg-white/10 dark:text-slate-400' }"
>
<span class="icon-[lucide--megaphone] h-5 w-5" aria-hidden="true" >
</span>
</span>
<span class="min-w-0">
<span class="block text-sm font-bold text-slate-950 dark:text-white">
Marketing cookies
</span>
<span class="mt-1 block text-xs leading-5 text-slate-600 dark:text-slate-400">
Measure campaigns and show relevant WRNexusJS content across supported services.
</span>
</span>
</span>
<span class="relative mt-0.5 shrink-0">
<input
type="checkbox"
name="marketing"
checked="{marketingCookies}"
@change="marketingCookies = event.target.checked"
class="peer sr-only"
/>
<span class="block h-6 w-11 rounded-full bg-slate-300 transition-colors duration-200 peer-checked:bg-rose-600 peer-focus-visible:ring-4 peer-focus-visible:ring-rose-500/20 dark:bg-slate-700" >
</span>
<span class="absolute left-1 top-1 h-4 w-4 rounded-full bg-white shadow-sm transition-transform duration-200 peer-checked:translate-x-5" >
</span>
</span>
</label>
</article>
</div>
<!-- Modal footer -->
<footer
class="border-t border-slate-200 bg-slate-50 px-5 py-4 dark:border-white/10 dark:bg-white/[0.02] sm:px-6"
>
<div class="grid gap-2 sm:grid-cols-3">
<button
type="button"
@click=" analyticsCookies = false; personalizationCookies = false; marketingCookies = false "
class="inline-flex h-11 items-center justify-center rounded-xl border border-slate-200 bg-white px-4 text-sm font-semibold text-slate-700 transition hover:border-slate-300 hover:bg-slate-100 hover:text-slate-950 dark:border-white/10 dark:bg-white/5 dark:text-slate-200 dark:hover:bg-white/10 dark:hover:text-white"
>
Reject optional
</button>
<button
type="button"
@click=" analyticsCookies = true; personalizationCookies = true; marketingCookies = true "
class="inline-flex h-11 items-center justify-center rounded-xl border border-indigo-200 bg-indigo-50 px-4 text-sm font-semibold text-indigo-700 transition hover:border-indigo-300 hover:bg-indigo-100 dark:border-indigo-500/20 dark:bg-indigo-500/10 dark:text-indigo-300 dark:hover:bg-indigo-500/15"
>
Enable all
</button>
<button
type="button"
@click=" preferencesOpen = false; bannerOpen = false "
data-cookie-action="save-preferences"
class="inline-flex h-11 items-center justify-center gap-2 rounded-xl bg-indigo-600 px-4 text-sm font-bold text-white shadow-lg shadow-indigo-600/20 transition hover:-translate-y-0.5 hover:bg-indigo-500 hover:shadow-xl"
>
<span class="icon-[lucide--save] h-4 w-4" aria-hidden="true" >
</span>
Save preferences
</button>
</div>
</footer>
</div>
</div>
</section>
</div>
}
}