Cookie consent

A React component in Beamline's Feedback category.

Asks once which cookies a visitor allows, with Reject all and Accept all given equal weight; Customise grows the notice in place into each category with its switch, purpose and the cookies behind it; the choice is remembered (and asked again when your policy changes), and a browser's Global Privacy Control keeps marketing off.

Use it for

  • Asking a site's or an app's visitors which optional cookies (analytics, marketing, functional) they allow, before any of them are set.
  • Letting people change that choice later from a Cookie settings link (open it again with `open`).

Not for

  • News, offers or maintenance notices (announcement-bar).
  • Notification permissions or other browser prompts (alert).
  • Account privacy settings with many options (settings).

Anatomy

  • notice: a card docked to a corner, a bar across the bottom, or in the page's flow; a size container
  • summary: what cookies are for in one sentence, a link to the policy, and Reject all · Customise · Accept all in one weight
  • preferences (the same card, grown): one row per category with its name, purpose, a switch (Always on for the necessary ones) and a fold with the cookies it sets (name, provider, purpose, how long it is kept)
  • a line when the browser sends Global Privacy Control: marketing stays off unless switched on here
  • footer of the preferences: Reject all · Accept all · Save choices
  • saved: a check and “Saved” for a moment, then the notice folds away

Variants

  • position: bottom-start, bottom-end, bottom, inline

States

  • asking (no remembered choice, or the policy version changed)
  • customising (preferences open)
  • saved (a moment, then closed)
  • closed (a choice is remembered)
  • global privacy control (marketing off by default, said in words)

Keyboard

  • The notice does not take focus or trap it: the page stays usable; Tab reaches it in reading order (it is a labelled region)
  • Customise moves focus to the first switch; Back returns it to Customise
  • Space toggles a switch; Enter or Space opens a category's cookie list
  • Escape in the preferences goes back to the summary; it never accepts or rejects anything

Motion

The notice rises in from its edge once. Customise grows the same card in place to the preferences (its width and height ease, the summary's buttons give way to the categories rising in one after another) and Back shrinks it again. Switches slide; a category's cookie list opens to its height. A decision shows a drawn check and Saved, then the card folds down and fades. Reduced motion keeps the fades.

Props

PropTypeDefaultDescription
categoriesConsentCategory[]—{ id, label, description, required?, cookies?: { name, provider, purpose, duration }[] }. Default: necessary, functional, analytics, marketing.
value / defaultValue / onValueChangeConsentChoice / (choice: ConsentChoice) => void—ConsentChoice = Record<categoryId, boolean>. onValueChange runs once per decision.
open / defaultOpen / onOpenChangeboolean—Uncontrolled, it opens when nothing is remembered for this version.
position"bottom-start" | "bottom-end" | "bottom" | "inline"—Default bottom-start.
storageKeystring | null—Where the decision is remembered. Default "pui-cookie-consent".
versionstring | number—Change it when your policy changes and everyone is asked again.
policyHref / policyLabelstring—The link in the summary. Default label “Cookie policy”.
title / descriptionReactNode—The summary's heading and sentence.
globalPrivacyControlboolean | "auto"—"auto" (default) reads the browser's signal; on the server pass what the Sec-GPC header said; false ignores it.
className / classNames / style / refroot—

Built from

  • button
  • switch

Dependencies

lucide-react, @radix-ui/react-switch

Import

import { CookieConsent, CONSENT_CATEGORIES } from "@/components/cookie-consent/cookie-consent";

Get it

Cookie consent is part of Beamline: 200+ components and 50+ complete screens for React that your coding agent (Claude Code, Codex, Cursor or any MCP client) installs into your app through Beamline's MCP server, as a ready-built package or as plain React source you can change. $49 launch price, one payment, no subscription, lifetime updates, one licence for your whole team. Get Beamline · Connect your agent

More in Feedback

  • Notification centre: Updates that wait to be read: a bell with the unread count opens All / Unread, new and earlier groups, and per item mark read or dismiss.
  • Usage meter: An allowance and what fills it: one bar split by source, the room left, a warning near the limit and the overflow in its own red well past a notch at the…
  • Alert: A message that stays until it is dealt with: what happened, what to do, an action; danger and warning are announced; dismissing folds its height away.
  • Empty state: What a place will hold and the first step to fill it, instead of a blank; a compact size for panels and filtered tables.
  • Spinner: A ring that spins while work runs and closes into a drawn check or cross when it ends.
  • Announcement bar: A banner across the top for news and offers: messages take turns, a countdown ticks, and dismissing folds it away and can remember it.
  • Progress: How much of a known task is done, or a moving bar when the length is unknown, with an optional label and value.
  • Skeleton: Holds the shape of content while it loads, then crossfades into it, so nothing jumps.