React Cookie Consent
Legally required across the EU, and almost universally implemented in bad faith. The constraints here are legal, not aesthetic — and getting them right costs nothing except the dark pattern.
We use cookies
Strictly necessary cookies keep the site working. Everything else is off until you turn it on. Read our cookie policy.
Installation
Props
| Prop | Type | Description |
|---|---|---|
| categories | ConsentCategory[] | { id, label, description, required?, vendors? } |
| policyHref | string | Link to your cookie policy |
| variant | "banner" \ | "panel" |
| onChange | (consent: ConsentState) => void | Fires on accept / reject / save |
The four rules it encodes
These are not style opinions. They are what regulators have repeatedly found consent banners failing on:
- Nothing optional is pre-enabled. Initial state sets every non-
requiredcategory tofalse. Pre-ticked boxes are not consent — the CJEU settled that in Planet49. - Reject is exactly as easy as accept. "Accept all" and "Reject all" are the same size, the same colour, side by side, both on the first screen. No greyed-out ghost button, no burying rejection behind "Manage preferences". This is the single most-cited violation, and it costs you one line of styling to avoid.
- Consent is withdrawable. After saving, the banner collapses to a summary with a "Change your choices" link, and
variant="panel"gives you the persistent settings surface to link from your footer. - Vendors are named.
vendorslists who actually receives the data per category. "Analytics" is not informed consent; "Google Analytics, Vercel Analytics" is.
Consent must gate the actual scripts
This component records a decision — it does not enforce it. Wire onChange so that no analytics or marketing script loads until its category is true, and so that revoking consent stops the collection. A banner that fires trackers on page load and asks afterwards is worse than no banner: you have the same violation plus written evidence you knew the rule.
Persist the result yourself (a first-party cookie or localStorage), along with a timestamp and the policy version consented to — you may need to demonstrate when and to what a user agreed. Note that the demo above resets on reload, because storing consent is your integration's job, not the component's.
Nothing here is legal advice; consult counsel for your jurisdiction. Different regimes differ — several US state laws are opt-out rather than opt-in, and Brazil's LGPD and others have their own requirements.
New components every week
Get the week's new Kelvin UI components and templates in one short email. No spam, unsubscribe anytime.