Component
Checkbox
Checkbox with checked, unchecked, indeterminate and disabled states.
Text referenceSource and examples as JSON
npx -y github:anwarlemu/opencommerce-brand-cli#release add checkbox --surface siteRun from the target React 19.2+ app root with Tailwind CSS 4 and the @/* source alias.
Usage
Use for multiple selections or a single agreement. Pair it with Label. When passing checked, update it through onCheckedChange.
- Round checkboxes
- Colors other than blue for checked
- A checkbox for an action that happens at once (use a switch)
Exports: Checkbox. This component includes a client boundary. Keep event handlers and state in a client component.
Dependencies: @radix-ui/react-checkbox, lucide-react.
Example
"use client";
import { useState } from "react";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
const MERCHANTS = [
{ id: "airlines", label: "Airlines", checked: true },
{ id: "hotels", label: "Hotels", checked: true },
{ id: "software", label: "Software subscriptions", checked: false },
];
export function Site() {
const [selected, setSelected] = useState(MERCHANTS.filter((merchant) => merchant.checked).map((merchant) => merchant.id));
return (
<fieldset className="grid gap-3">
<legend className="mb-3 font-display text-caption text-fg-muted">What this card can buy</legend>
{MERCHANTS.map((merchant) => (
<Label variant="control" key={merchant.id} htmlFor={`checkbox-${merchant.id}`}>
<Checkbox id={`checkbox-${merchant.id}`} checked={selected.includes(merchant.id)} onCheckedChange={(checked) => setSelected((current) => checked ? [...current, merchant.id] : current.filter((id) => id !== merchant.id))} />
{merchant.label}
</Label>
))}
<Label variant="control" htmlFor="checkbox-all" className="mt-2">
<Checkbox id="checkbox-all" checked={selected.length === MERCHANTS.length ? true : selected.length ? "indeterminate" : false} onCheckedChange={(checked) => setSelected(checked ? MERCHANTS.map((merchant) => merchant.id) : [])} />
All categories
</Label>
<Label variant="control" htmlFor="checkbox-disabled">
<Checkbox id="checkbox-disabled" disabled />
Cash withdrawals (never allowed)
</Label>
</fieldset>
);
}Source
"use client";
import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { Check, Minus } from "lucide-react";
import { cn } from "@/lib/utils";
// A small key: an 18px white box with 5px corners on the 16 percent ink edge; checked, it becomes the blue key (its
// darker blue edge) with a white check. The fill changes in 160ms ease-out.
function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"peer grid size-4.5 shrink-0 place-items-center rounded-menu border border-hairline bg-surface text-on-primary outline-none transition-[background-color,border-color] duration-160 ease-out focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus-ring disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-danger data-[state=checked]:border-line-brand-edge data-[state=checked]:bg-primary data-[state=indeterminate]:border-line-brand-edge data-[state=indeterminate]:bg-primary motion-reduce:transition-none",
className,
)}
{...props}
>
<CheckboxPrimitive.Indicator data-slot="checkbox-indicator" className="grid place-items-center [&_svg]:size-3">
{props.checked === "indeterminate" ? <Minus strokeWidth={2.25} /> : <Check strokeWidth={2.25} />}
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
);
}
export { Checkbox };Reference: Extension from opencommerce-agentcard-web src/app/globals.css (.btn-primary, --bevel-edge-blue).