Skip to content
W WRNexusJS
core component

CookieConsent

Reusable cookie consent component.

@wrnexus/ui 0.2.671 props0 slots2 events

Usage

Components are auto-discovered. Use the component directly in any .wrn view:

<CookieConsent />

Legacy mount name: data-component="CookieConsent".

Props and attributes

PropTypeRequirementDefault
classstringOptional""

Slots

This component does not declare a slot.

Events

  • click
  • change

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>
    }
}