Core Component
Checkbox
Binary or tri-state checkbox with spring-animated check icon, label, and description.
Preview
Stream responses
Show AI responses as they generate
Enable tool use
Allow the model to call external tools
Select all
Locked setting
Source
Full component implementation using the design system tokens.
"use client";
import { useState } from "react";
import { Check, Minus } from "lucide-react";
export function DSCheckbox({
checked: controlledChecked,
defaultChecked = false,
onChange,
label,
description,
indeterminate = false,
disabled = false,
}: {
checked?: boolean;
defaultChecked?: boolean;
onChange?: (checked: boolean) => void;
label?: string;
description?: string;
indeterminate?: boolean;
disabled?: boolean;
}) {
const [internalChecked, setInternalChecked] = useState(defaultChecked);
const isControlled = controlledChecked !== undefined;
const checked = isControlled ? controlledChecked : internalChecked;
const toggle = () => {
if (disabled) return;
const next = !checked;
if (!isControlled) setInternalChecked(next);
onChange?.(next);
};
const isActive = checked || indeterminate;
return (
<div className="flex items-start gap-3">
<button
role="checkbox"
aria-checked={indeterminate ? "mixed" : checked}
onClick={toggle}
disabled={disabled}
className={`relative inline-flex items-center justify-center w-5 h-5 shrink-0 rounded-md border-2 transition-all duration-150 active:scale-[0.95] mt-0.5 ${isActive ? "bg-accent border-accent" : "border-overlay/15 hover:border-overlay/25"} ${disabled ? "opacity-50 cursor-not-allowed active:scale-100" : ""}`}
style={{ transitionTimingFunction: "var(--ease-out)" }}
>
{indeterminate ? (
<Minus className="w-3.5 h-3.5 text-background" />
) : (
<Check className="w-3.5 h-3.5 text-background" style={{
opacity: checked ? 1 : 0,
transform: checked ? "scale(1)" : "scale(0.5)",
transition: "opacity 150ms var(--ease-out), transform 200ms var(--ease-out)",
}} />
)}
</button>
{(label || description) && (
<div className={disabled ? "opacity-50" : "cursor-pointer"} onClick={disabled ? undefined : toggle}>
{label && <p className="text-sm font-medium text-foreground">{label}</p>}
{description && <p className="text-xs text-tertiary mt-0.5">{description}</p>}
</div>
)}
</div>
);
}Props
All available props with types and defaults.
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | — | Controlled checked state |
defaultChecked | boolean | false | Initial checked state (uncontrolled) |
onChange | (checked: boolean) => void | — | Called when checked state changes |
label | string | — | Label text |
description | string | — | Helper text below label |
indeterminate | boolean | false | Shows minus icon for partial state |
disabled | boolean | false | Disables the checkbox |
Variants
Default
Basic checkbox with label.
Enable streaming
<DSCheckbox label="Enable streaming" />With Description
Checkbox with label and helper text.
Tool use
Allow the model to call external tools
<DSCheckbox label="Tool use" description="Allow the model to call external tools" />Indeterminate
Partial selection state for parent checkboxes.
Select all
<DSCheckbox indeterminate label="Select all" />Disabled
Non-interactive disabled state.
Locked setting
<DSCheckbox disabled label="Locked setting" />Prompt Guide
Prompt Guide — Checkbox
Use for
- Multi-select settings (enable tools, features)
- Terms and conditions acceptance
- Bulk selection with indeterminate parent
- Filter toggles in search interfaces
Don't use for
- Single on/off — use Toggle for binary switches
- Mutually exclusive options — use Radio group
- Momentary actions — use Button instead
AI Context
Check icon animates from scale(0.5) to scale(1) with opacity for a spring-like feel. The indeterminate state uses a Minus icon for 'select all' parent checkboxes. Supports both controlled and uncontrolled patterns.