Checkbox
Client leafA control that toggles a boolean or shows an indeterminate state.
Live preview
Rendered from the installed VEXA source — the same files you receive.
Installation
Adds the component source to your project. Registry dependencies are pulled in automatically.
npx shadcn@latest add https://vexa.valfiguer.com/r/checkbox.jsonInstalls to components/vexa/checkbox.tsx
npm dependencies
- @radix-ui/react-checkbox
Registry dependencies
- @vexa/utils
Other VEXA items this component needs. Install them first — they are resolved automatically by the CLI.
Source
Copy this into its target path, or install it with the command above.
components/vexa/checkbox.tsx
"use client";
import type * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { cn } from "@/lib/utils";
function CheckIcon({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
className={className}
>
<path
d="M4 12.5 9 17.5 20 6.5"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}
function MinusIcon({ className }: { className?: string }) {
return (
<svg
viewBox="0 0 24 24"
fill="none"
aria-hidden="true"
className={className}
>
<path
d="M6 12h12"
stroke="currentColor"
strokeWidth="2.5"
strokeLinecap="round"
/>
</svg>
);
}
/**
* Checkbox — a control that toggles a boolean, or represents an indeterminate
* (mixed) state. Built on Radix so the role, `aria-checked` (including
* `"mixed"`), keyboard model (Space toggles), and label association are handled.
*
* Client leaf: the `"use client"` boundary lives here. Pair with `<Label>` via
* a shared `id`, or wrap the label text so a click on it toggles the control.
* The checked/indeterminate state is conveyed by an icon, not color alone.
*/
export function Checkbox({
className,
...props
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"group peer size-5 shrink-0 rounded-vexa-sm border border-vexa-input bg-vexa-surface-raised shadow-vexa-sm",
"transition-[color,background-color,border-color,box-shadow] duration-[var(--vexa-duration-fast)] ease-[var(--vexa-ease-standard)]",
"outline-none focus-visible:ring-2 focus-visible:ring-vexa-ring focus-visible:ring-offset-2 focus-visible:ring-offset-vexa-background",
"disabled:cursor-not-allowed disabled:opacity-50",
"data-[state=checked]:border-vexa-primary data-[state=checked]:bg-vexa-primary data-[state=checked]:text-vexa-primary-foreground",
"data-[state=indeterminate]:border-vexa-primary data-[state=indeterminate]:bg-vexa-primary data-[state=indeterminate]:text-vexa-primary-foreground",
"aria-[invalid=true]:border-vexa-danger",
className,
)}
{...props}
>
<CheckboxPrimitive.Indicator
data-slot="checkbox-indicator"
className="flex items-center justify-center text-current"
>
<CheckIcon className="size-3.5 group-data-[state=indeterminate]:hidden" />
<MinusIcon className="hidden size-3.5 group-data-[state=indeterminate]:block" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
);
}
Details
Example
tsx
<div className="flex items-center gap-2"><Checkbox id="terms" /><Label htmlFor="terms">Accept terms</Label></div>Accessibility
Radix supplies role=checkbox, aria-checked (including "mixed"), and Space to toggle. Checked/indeterminate shown by an icon, not color alone. Associate a <Label>.