Checkbox
A control that allows the user to toggle between checked and not checked.
Installation
bash
npx @smicolon/fasla-ui@latest add checkboxRun init once per project before adding components. See Installation.
Preview
Variants
Two types, as in Figma. default is the box and its label on their own. layout wraps them in a bordered card that is all one click target, and fills on hover.
defaultlayoutSizes
Three sizes. md is the default. The box is 16, 20 or 24px, and the label stays the same size.
defaultlayoutStates
Checked shows a tick, indeterminate shows a dash, and neither flips in right-to-left. Hover and focus are real CSS states rather than props. Hover a checkbox, or tab to it, to see them. Disabled dims the whole checkbox, label and description included.
defaultlayoutAccessibility
- Renders a native
<input type="checkbox">, so Space toggles it and it submits with a form without extra code. indeterminatesets the input's own property, so a screen reader announces the checkbox as mixed. A click clears it, as in the browser; keep the prop in step from your state.- The checkbox is named by
labelalone, anddescriptionis linked witharia-describedby. The box is hidden from assistive technology. - Without a
label, pass anaria-label. - Direction is inherited from
dir, never a prop. The box sits at the start of the line in both directions.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "layout" | "default" | The box on its own, or inside a bordered card. |
size | "sm" | "md" | "lg" | "md" | Checkbox size. |
checked | boolean | — | Checked state. Use it with onChange. |
defaultChecked | boolean | false | Starting state when you do not control it. |
indeterminate | boolean | false | Shows a dash for a partly selected group. |
disabled | boolean | false | Disables the checkbox and dims it. |
label | string | — | Label text. |
description | string | — | Secondary line below the label. |
name | string | — | Name submitted with the form. |
value | string | — | Value submitted when checked. |
onChange | (event) => void | — | Called when the checkbox changes. |
className | string | — | Extra classes for the component. |
Usage
Basic checkbox
tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export function TermsCheckbox() {
return <Checkbox name="terms" aria-label="Accept terms and conditions" />
}With label
tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export function TermsCheckbox() {
return <Checkbox name="terms" label="Accept terms and conditions" />
}With description
tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export function MarketingCheckbox() {
return (
<Checkbox
name="marketing"
label="Marketing emails"
description="Receive emails about new products and features"
/>
)
}Layout card
tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export function SecurityCheckbox() {
return <Checkbox name="security" variant="layout" label="Security alerts" />
}Different sizes
tsx
"use client"
import { Checkbox } from "@/components/ui/checkbox"
export function CheckboxSizes() {
return (
<div className="flex flex-col gap-3">
<Checkbox size="sm" label="Small" />
<Checkbox size="md" label="Medium" />
<Checkbox size="lg" label="Large" />
</div>
)
}Select all, with an indeterminate parent
tsx
"use client"
import { useState } from "react"
import { Checkbox } from "@/components/ui/checkbox"
const files = ["Annual report.pdf", "Invoices.xlsx", "Contract.docx"]
export function SelectAllFiles() {
const [selected, setSelected] = useState<string[]>([])
const all = selected.length === files.length
return (
<div className="flex flex-col gap-3">
<Checkbox
label="Select all files"
checked={all}
indeterminate={selected.length > 0 && !all}
onChange={(e) => setSelected(e.target.checked ? files : [])}
/>
<div className="flex flex-col gap-3 ps-8">
{files.map((file) => (
<Checkbox
key={file}
size="sm"
label={file}
checked={selected.includes(file)}
onChange={(e) =>
setSelected((prev) =>
e.target.checked ? [...prev, file] : prev.filter((f) => f !== file)
)
}
/>
))}
</div>
</div>
)
}Files selected: 1