A Radix Checkbox whose check draws in via a stroke-dashoffset transition — rapid toggling retargets mid-draw — with an indeterminate state.
npx shadcn@latest add @paragon/checkbox"use client";
import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { cn } from "@/lib/utils";
export interface CheckboxProps
extends React.ComponentProps<typeof CheckboxPrimitive.Root> {}
/**
* Radix Checkbox with a path-draw check. The check is a permanently mounted
* SVG path whose stroke-dashoffset transitions between 1 and 0, so rapid
* toggling retargets mid-draw instead of restarting. Supports the
* `indeterminate` checked state (drawn dash).
*/
export function Checkbox({ className, ...props }: CheckboxProps) {
return (
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"group peer relative size-4 shrink-0 rounded-[5px] border border-input bg-transparent",
"transition-[background-color,border-color,box-shadow] duration-150 ease-out",
"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
"data-[state=checked]:border-primary data-[state=checked]:bg-primary",
"data-[state=indeterminate]:border-primary data-[state=indeterminate]:bg-primary",
"disabled:cursor-not-allowed disabled:opacity-50",
// Extend the hit area to 40px without growing the visual.
"after:absolute after:top-1/2 after:left-1/2 after:size-10 after:-translate-x-1/2 after:-translate-y-1/2",
className,
)}
{...props}
>
<span
aria-hidden
className="pointer-events-none absolute inset-0 flex items-center justify-center text-primary-foreground"
>
<svg
viewBox="0 0 12 12"
fill="none"
stroke="currentColor"
strokeWidth={1.75}
strokeLinecap="round"
strokeLinejoin="round"
className="size-3"
>
{/* Check — drawn when checked. */}
<path
d="M2.25 6.4 4.9 9 9.75 3.5"
pathLength={1}
className={cn(
"[stroke-dasharray:1] [stroke-dashoffset:1]",
"transition-[stroke-dashoffset] duration-200 ease-out motion-reduce:transition-none",
"group-data-[state=checked]:[stroke-dashoffset:0]",
)}
/>
{/* Dash — drawn when indeterminate. */}
<path
d="M2.75 6h6.5"
pathLength={1}
className={cn(
"[stroke-dasharray:1] [stroke-dashoffset:1]",
"transition-[stroke-dashoffset] duration-200 ease-out motion-reduce:transition-none",
"group-data-[state=indeterminate]:[stroke-dashoffset:0]",
)}
/>
</svg>
</span>
</CheckboxPrimitive.Root>
);
}