Forms
Checkbox
Checkbox whose tick draws itself in, with indeterminate, invalid and choice-card states.
Patterns only. Never a customer’s words or identity.
pnpm dlx shadcn@latest add @paragon/checkboxBrings in@base-ui/reactcn
States
The tick draws itself in; the box springs when pressed. Focus is the same 2px offset ring as Button.
| Rest | Hover | Focus | Pressed | Invalid | Disabled | |
|---|---|---|---|---|---|---|
| unchecked | ||||||
| checked | ||||||
| indeterminate |
Group
The parent goes indeterminate when only some channels are on.
registry/paragon/ui/checkbox.tsx
"use client"
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
import { cn } from "cn"
/**
* The tick draws itself in when checked and fades out when cleared.
* Pass `indeterminate` for a parent of a partially selected group.
*/
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"peer relative flex size-[1.125rem] shrink-0 items-center justify-center rounded-[0.3125rem] border border-input bg-card text-primary-foreground outline-none",
"[transition:background-color_var(--duration-base)_var(--ease-paragon),border-color_var(--duration-base)_var(--ease-paragon),scale_var(--duration-slow)_var(--ease-spring)]",
"after:absolute after:-inset-2.5",
"hover:border-foreground/45",
"active:scale-90 active:[transition-duration:var(--duration-fast)] motion-reduce:active:scale-100",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:outline-solid",
"data-checked:border-primary data-checked:bg-primary data-indeterminate:border-primary data-indeterminate:bg-primary",
"aria-invalid:border-destructive aria-invalid:focus-visible:outline-destructive aria-invalid:data-checked:border-primary",
"data-disabled:pointer-events-none data-disabled:opacity-50",
"dark:bg-input/15",
// Inside a choice card the card carries the focus ring instead.
"group-has-[:focus-visible]/field-label:outline-none",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator
data-slot="checkbox-indicator"
className="group/indicator flex items-center justify-center transition-opacity duration-(--duration-fast) data-ending-style:opacity-0"
>
<svg viewBox="0 0 12 12" fill="none" aria-hidden="true" className="size-3 stroke-current">
<path
d="M2.5 6.25 5 8.75 9.75 3.5"
pathLength={1}
strokeWidth={1.75}
strokeLinecap="round"
strokeLinejoin="round"
className="transition-[stroke-dashoffset] duration-(--duration-slow) ease-paragon [stroke-dasharray:1] [stroke-dashoffset:0] group-data-indeterminate/indicator:hidden group-data-starting-style/indicator:[stroke-dashoffset:1] motion-reduce:transition-none"
/>
<path
d="M3 6h6"
pathLength={1}
strokeWidth={1.75}
strokeLinecap="round"
className="hidden transition-[stroke-dashoffset] duration-(--duration-base) ease-paragon [stroke-dasharray:1] [stroke-dashoffset:0] group-data-indeterminate/indicator:block group-data-starting-style/indicator:[stroke-dashoffset:1] motion-reduce:transition-none"
/>
</svg>
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
)
}
export { Checkbox }