InputsCheckbox
Checkbox
Native input, custom skin. The label is the click target, not just the box.
States
Unchecked, checked, indeterminate, disabled. The label is the click target; the box is the visual indicator.
States
Anatomy
- 16 × 16 px box, 2 px radius, 1 px
--borderat rest - Checked:
--foregroundbackground,--backgroundcheck - Indeterminate:
--foregroundbackground,--backgroundbar - Focus ring is the system default applied to the input
- Label is set in 0.9375 rem, attached by
htmlFor
Implementation
checkbox.tsx
import { forwardRef, useEffect, useRef, type InputHTMLAttributes } from "react"
import { Check } from "lucide-react"
import SiteIcon from "@/components/site-icon"
interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
label: string
indeterminate?: boolean
}
export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
function Checkbox({ label, indeterminate, className, ...props }, ref) {
const innerRef = useRef<HTMLInputElement | null>(null)
useEffect(() => {
if (innerRef.current) innerRef.current.indeterminate = !!indeterminate
}, [indeterminate])
return (
<label className={cn("ds-checkbox", className)}>
<input
ref={(node) => {
if (typeof ref === "function") ref(node)
innerRef.current = node
}}
type="checkbox"
{...props}
/>
<span className="ds-checkbox__box" aria-hidden="true">
{indeterminate ? <span className="ds-checkbox__bar" /> : <SiteIcon icon={Check} size="xs" />}
</span>
<span className="ds-checkbox__label">{label}</span>
</label>
)
},
)Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | None | Required: the label |
checked | boolean | false | Checked state |
indeterminate | boolean | false | Indeterminate state |
disabled | boolean | false | Disabled state |