# Checkbox Draw Check — React Checkbox Component

> A checkbox whose fill springs out from the centre while the tick is drawn as a single pen stroke, then erased in reverse when cleared.

- Category: [Checkboxes & Radios](https://pixelpapa.com/components/checkboxes.md)
- Tags: checkbox, check, draw, svg, form
- Dependencies: motion (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/checkboxes/checkbox-draw-check

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/checkbox-draw-check.json"
```

The file is written to `components/pixelpapa/checkbox-draw-check.tsx`. To install manually, run `npm install motion` and copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import { motion } from "motion/react";
import { useState, type ReactNode } from "react";
import { cn } from "@/lib/utils";

type DrawCheckboxProps = {
  children: ReactNode;
  description?: ReactNode;
  checked?: boolean;
  defaultChecked?: boolean;
  onCheckedChange?: (checked: boolean) => void;
  shape?: "square" | "circle";
  disabled?: boolean;
  className?: string;
};

export function DrawCheckbox({
  children,
  description,
  checked,
  defaultChecked = false,
  onCheckedChange,
  shape = "square",
  disabled = false,
  className,
}: DrawCheckboxProps) {
  const [internal, setInternal] = useState(defaultChecked);
  const on = checked ?? internal;
  const radius = shape === "circle" ? "rounded-full" : "rounded-md";

  return (
    <label
      className={cn(
        "group flex items-start gap-3",
        disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
        className,
      )}
    >
      <motion.span whileTap={disabled ? undefined : { scale: 0.86 }} className="relative mt-0.5 size-5 shrink-0">
        <input
          type="checkbox"
          checked={on}
          disabled={disabled}
          onChange={(e) => {
            setInternal(e.target.checked);
            onCheckedChange?.(e.target.checked);
          }}
          className="peer absolute inset-0 z-10 size-full cursor-[inherit] opacity-0"
        />
        <span
          aria-hidden
          className={cn(
            "absolute inset-0 border-[1.5px] border-input bg-card transition-colors duration-200 group-hover:border-primary/60 peer-focus-visible:ring-2 peer-focus-visible:ring-ring peer-focus-visible:ring-offset-2 peer-focus-visible:ring-offset-background",
            radius,
          )}
        />
        <motion.span
          aria-hidden
          initial={false}
          animate={{ scale: on ? 1 : 0.3, opacity: on ? 1 : 0 }}
          transition={{ type: "spring", stiffness: 520, damping: 26 }}
          className={cn("absolute inset-0 bg-primary", radius)}
        />
        <svg aria-hidden viewBox="0 0 20 20" fill="none" className="absolute inset-0 text-primary-foreground">
          <motion.path
            d="M5.5 10.4l3.1 3.1 6-6.8"
            stroke="currentColor"
            strokeWidth="2.2"
            strokeLinecap="round"
            strokeLinejoin="round"
            initial={false}
            animate={{ pathLength: on ? 1 : 0, opacity: on ? 1 : 0 }}
            transition={{
              pathLength: { duration: on ? 0.28 : 0.16, delay: on ? 0.1 : 0, ease: "easeOut" },
              opacity: { duration: 0.01, delay: on ? 0.1 : 0.15 },
            }}
          />
        </svg>
      </motion.span>
      <span className="min-w-0 select-none">
        <span className="block text-sm font-medium text-foreground">{children}</span>
        {description && <span className="mt-0.5 block text-xs text-muted-foreground">{description}</span>}
      </span>
    </label>
  );
}

export default function CheckboxDrawCheckDemo() {
  return (
    <div className="w-full max-w-sm rounded-2xl border border-border bg-card p-5">
      <p className="text-sm font-semibold text-card-foreground">Before you deploy</p>
      <div className="mt-4 flex flex-col gap-4">
        <DrawCheckbox defaultChecked description="Run on the staging database first.">
          Migrations are reversible
        </DrawCheckbox>
        <DrawCheckbox defaultChecked description="p95 under 300 ms for the last 24 hours.">
          Load test passed
        </DrawCheckbox>
        <DrawCheckbox description="Post in #releases so support is not surprised.">Team has been notified</DrawCheckbox>
        <DrawCheckbox disabled description="Requires the Enterprise plan.">
          Canary rollout to 5% of traffic
        </DrawCheckbox>
      </div>
      <div className="mt-5 flex gap-6 border-t border-border pt-4">
        <DrawCheckbox shape="circle" defaultChecked>
          Remember this device
        </DrawCheckbox>
        <DrawCheckbox shape="circle">Email me a receipt</DrawCheckbox>
      </div>
    </div>
  );
}
```

## AI prompt

```text
Add the "Checkbox Draw Check" component from PixelPapa UI to this project.

What it is: A checkbox whose fill springs out from the centre while the tick is drawn as a single pen stroke, then erased in reverse when cleared.
Category: Checkboxes & Radios. Depends on: motion.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/checkbox-draw-check.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/checkbox-draw-check.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/checkbox-draw-check" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More checkboxes & radios

- [Checkbox Card Select](https://pixelpapa.com/components/checkboxes/checkbox-card-select.md) (Pro): Multi-select cards: a chosen card tints, its icon tile inverts and a check bubble springs into the corner while the running total rolls.
- [Checkbox Indeterminate Tree](https://pixelpapa.com/components/checkboxes/checkbox-indeterminate-tree.md) (Pro): A nested checkbox tree where parents reflect their children: the mark morphs between a dash and a check, and branches fold open with animated height.
- [Checkbox Todo Strikethrough](https://pixelpapa.com/components/checkboxes/checkbox-todo-strikethrough.md): A to-do list where ticking an item draws a line through its text from left to right, then the finished item sinks to the bottom with a layout spring.
- [Radio Card Plans](https://pixelpapa.com/components/checkboxes/radio-card-plans.md): Plan cards backed by native radios: one shared selection ring glides from card to card with a spring while the radio dot pops in.
- [Radio Segmented Dots](https://pixelpapa.com/components/checkboxes/radio-segmented-dots.md) (Pro): A minimal radio group of dots on a hairline: a ringed marker bounces between them on a spring and the chosen option's name rolls in beside the label.
