DesignCheckbox
A circular selection indicator with animated check icon. Supports multi-select (checkbox), single-select with deselect (radio-like), and toggle scenarios.
Component
Import
tsx
import { DesignCheckbox } from "@/components/ui/design-checkbox";
Type
Selection Indicator
Sizes
small, default, large
Use Cases
multi/single/toggle
Shape
Circular

Live Examples

Interactive examples demonstrating component usage

Basic Checkbox

Click to toggle

const [checked, setChecked] = useState(false);

<button onClick={() => setChecked(!checked)} className="flex items-center gap-2">
  <DesignCheckbox checked={checked} />
  <span>Label</span>
</button>

Single-Select (Radio-like)

One option at a time

const [mode, setMode] = useState<"niche" | "similar">("niche");

<button onClick={() => setMode("niche")} className="...">
  <DesignCheckbox checked={mode === "niche"} />
  <span>Niche Mode</span>
</button>
<button onClick={() => setMode("similar")} className="...">
  <DesignCheckbox checked={mode === "similar"} />
  <span>Similar Mode</span>
</button>

Sizes

small, default, large

small
default
large
<DesignCheckbox size="small" checked />
<DesignCheckbox size="default" checked />
<DesignCheckbox size="large" checked />

States

All visual states

unchecked
checked
disabled
disabled+checked
<DesignCheckbox checked={false} />
<DesignCheckbox checked={true} />
<DesignCheckbox disabled />
<DesignCheckbox disabled checked />

Multi-Select List

Checkbox list pattern

{items.map(item => (
  <button
    key={item.id}
    onClick={() => toggleItem(item.id)}
    className="flex items-center gap-3 ..."
  >
    <DesignCheckbox checked={item.checked} />
    <span>{item.label}</span>
  </button>
))}

API Reference

Props
PropTypeDefaultDescription
checkedbooleanfalseWhether the checkbox is checked (display only)
disabledbooleanfalseApplies disabled visual style (50% opacity)
size"small" | "default" | "large""default"Size variant (16px, 20px, 24px)
classNamestring-Additional CSS classes
Common Patterns

Basic Toggle

Simple on/off state
const [checked, setChecked] = useState(false);

<button
  onClick={() => setChecked(!checked)}
  className="flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-surface-200"
>
  <DesignCheckbox checked={checked} />
  <span>Toggle me</span>
</button>

Single-Select (Radio-like)

One option at a time
type Mode = "niche" | "similar";
const [mode, setMode] = useState<Mode>("niche");

<div className="flex flex-col gap-1">
  <button onClick={() => setMode("niche")} className="flex items-center gap-3 ...">
    <DesignCheckbox checked={mode === "niche"} />
    <span>Niche Mode</span>
  </button>
  <button onClick={() => setMode("similar")} className="flex items-center gap-3 ...">
    <DesignCheckbox checked={mode === "similar"} />
    <span>Similar Mode</span>
  </button>
</div>

Multi-Select List

Multiple items can be selected
const [items, setItems] = useState([
  { id: 1, label: "Email notifications", checked: true },
  { id: 2, label: "Push notifications", checked: false },
]);

const toggle = (id: number) => {
  setItems(items.map(item =>
    item.id === id ? { ...item, checked: !item.checked } : item
  ));
};

{items.map(item => (
  <button
    key={item.id}
    onClick={() => toggle(item.id)}
    className="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-surface-200"
  >
    <DesignCheckbox checked={item.checked} />
    <span>{item.label}</span>
  </button>
))}

Selection Card Pattern

With title and description
<button
  onClick={() => setSelected(!selected)}
  className="flex items-center gap-3 w-full px-3 py-2.5 rounded-lg hover:bg-surface-200 text-left"
>
  <DesignCheckbox checked={selected} />
  <div>
    <span className="text-sm font-medium">{title}</span>
    <p className="text-xs text-secondary">{description}</p>
  </div>
</button>
Do

Always wrap in a clickable parent (button/div with onClick)

<button onClick={() => setChecked(!checked)} className="flex items-center gap-3">
  <DesignCheckbox checked={checked} />
  <span>Label text</span>
</button>

Use for multi-select (checkbox) scenarios

Use for single-select when switching between options

Don't

Don't use DesignCheckbox standalone - it's a display-only indicator

Don't use for radio groups where one option must always be selected

Don't wrap in <label> - use <button> with onClick instead

When to Use
1

Single-Select Mode Picker

Use when user can deselect or switch between modes

// Mode can be "niche", "similar", or null (none selected)
<div className="flex flex-col gap-1">
  <button onClick={() => setMode("niche")} className="flex items-center gap-3 px-3 py-2 ...">
    <DesignCheckbox checked={mode === "niche"} />
    <div>
      <span className="font-medium">Niche Mode</span>
      <p className="text-xs text-secondary">Find niche-specific content</p>
    </div>
  </button>
  <button onClick={() => setMode("similar")} className="flex items-center gap-3 px-3 py-2 ...">
    <DesignCheckbox checked={mode === "similar"} />
    <div>
      <span className="font-medium">Similar Mode</span>
      <p className="text-xs text-secondary">Find similar accounts</p>
    </div>
  </button>
</div>
2

Settings Toggles

Use for on/off preferences

<label className="flex items-center justify-between p-3 rounded-lg hover:bg-surface-200">
  <span>Enable dark mode</span>
  <DesignCheckbox
    checked={darkMode}
    onCheckedChange={setDarkMode}
  />
</label>
3

Multi-Select List

Use for selecting multiple items from a list

{users.map(user => (
  <label key={user.id} className="flex items-center gap-3 p-2">
    <DesignCheckbox
      checked={selectedIds.includes(user.id)}
      onCheckedChange={() => toggleSelection(user.id)}
    />
    <Avatar src={user.avatar} />
    <span>{user.name}</span>
  </label>
))}

Design Specifications

Unchecked State
  • β€’ Border: 1.5px solid border-secondary
  • β€’ Border radius: 50% (full circle)
  • β€’ Background: transparent
  • β€’ Icon: hidden (opacity 0, scale 0.75)
Checked State
  • β€’ Background: var(--primary) @ 6%
  • β€’ Border: transparent
  • β€’ Icon: check-bold, var(--primary)
  • β€’ Icon: visible (opacity 1, scale 1)
Sizes
  • β€’ small: 16Γ—16px, icon 10px
  • β€’ default: 20Γ—20px, icon 12px
  • β€’ large: 24Γ—24px, icon 14px
Animation
  • β€’ Duration: 200ms
  • β€’ Easing: ease-out
  • β€’ Properties: opacity, transform, background
Disabled State
  • β€’ Opacity: 50%
  • β€’ Cursor: not-allowed
  • β€’ No hover effect
Usage Pattern
  • β€’ Display-only indicator
  • β€’ Has pointer-events: none
  • β€’ Must wrap in clickable parent
  • β€’ Parent handles click events