Checkbox

Select individual options, filters, and consent choices.

Handle independent choices in forms and settings. Keep the control simple, add supporting text, or place it in a selectable card.

tsx
import * as React from "react"import { Card, CardContent } from "@/components/ui/card"import { Checkbox } from "@/components/ui/checkbox"import { cn } from "@/lib/utils"export function Example() {  const [checked, setChecked] = React.useState(false)  return (    <>      <label className="flex items-center gap-2.5 text-sm tracking-wide">        <Checkbox defaultChecked id="basic" />        Sync local registry on save      </label>      <label className="flex items-start gap-2.5">        <Checkbox id="described" className="mt-0.5" />        <span className="grid gap-1">          <span className="text-sm font-medium tracking-wide">            Watch theme tokens          </span>          <span className="text-sm text-muted-foreground">            Rebuild docs when CSS variables change under globals.css.          </span>        </span>      </label>      <label className="flex items-center gap-2.5 text-sm tracking-wide opacity-60">        <Checkbox disabled id="disabled" />        Publish package — unlock after review      </label>      <label className="block w-full cursor-pointer">        <Card className={cn("py-0", !checked && "bg-transparent")}>          <CardContent className="flex items-start gap-2.5 py-3">            <Checkbox              id="card"              checked={checked}              onCheckedChange={setChecked}              className="mt-0.5"            />            <span className="grid gap-1">              <span className="text-sm font-medium tracking-wide">                Include in docs build              </span>              <span className="text-sm text-muted-foreground">                Ships markdown, demos, and tokens with the registry export.              </span>            </span>          </CardContent>        </Card>      </label>    </>  )}

Installation

npx @arctis-sh/@arctis-sh/ui@latest add checkbox

Usage

import { Checkbox } from "@/components/ui/checkbox"
<label className="flex items-center gap-2.5 text-sm tracking-wide">  <Checkbox id="sync" />  Sync local registry on save</label>
<Checkbox  checked={checked}  onCheckedChange={setChecked}/>

Basic

The common patterns: a plain row, supporting description, disabled state, and selectable card.

tsx
import * as React from "react"import { Card, CardContent } from "@/components/ui/card"import { Checkbox } from "@/components/ui/checkbox"import { cn } from "@/lib/utils"export function Example() {  const [checked, setChecked] = React.useState(false)  return (    <>      <label className="flex items-center gap-2.5 text-sm tracking-wide">        <Checkbox defaultChecked id="basic" />        Sync local registry on save      </label>      <label className="flex items-start gap-2.5">        <Checkbox id="described" className="mt-0.5" />        <span className="grid gap-1">          <span className="text-sm font-medium tracking-wide">            Watch theme tokens          </span>          <span className="text-sm text-muted-foreground">            Rebuild docs when CSS variables change under globals.css.          </span>        </span>      </label>      <label className="flex items-center gap-2.5 text-sm tracking-wide opacity-60">        <Checkbox disabled id="disabled" />        Publish package — unlock after review      </label>      <label className="block w-full cursor-pointer">        <Card className={cn("py-0", !checked && "bg-transparent")}>          <CardContent className="flex items-start gap-2.5 py-3">            <Checkbox              id="card"              checked={checked}              onCheckedChange={setChecked}              className="mt-0.5"            />            <span className="grid gap-1">              <span className="text-sm font-medium tracking-wide">                Include in docs build              </span>              <span className="text-sm text-muted-foreground">                Ships markdown, demos, and tokens with the registry export.              </span>            </span>          </CardContent>        </Card>      </label>    </>  )}

Card

Place the control in a Card with a title and description. The outlined card fills when selected.

tsx
import * as React from "react"import { Card, CardContent } from "@/components/ui/card"import { Checkbox } from "@/components/ui/checkbox"import { cn } from "@/lib/utils"export function Example() {  const [checked, setChecked] = React.useState(false)  return (    <label className="block w-full cursor-pointer">      <Card className={cn("py-0", !checked && "bg-transparent")}>        <CardContent className="flex items-start gap-2.5 py-3">          <Checkbox            id="card-option"            checked={checked}            onCheckedChange={setChecked}            className="mt-0.5"          />          <span className="grid gap-1">            <span className="text-sm font-medium tracking-wide">              Include in docs build            </span>            <span className="text-sm text-muted-foreground">              Ships markdown, demos, and tokens with the registry export.            </span>          </span>        </CardContent>      </Card>    </label>  )}

Controlled

Pass checked and onCheckedChange when the parent owns the value. Use defaultChecked to set an initial uncontrolled value.

tsx
import * as React from "react"import { Checkbox } from "@/components/ui/checkbox"export function Example() {  const [checked, setChecked] = React.useState(false)  return (    <label className="flex items-center gap-2.5 text-sm tracking-wide">      <Checkbox        id="dark-preview"        checked={checked}        onCheckedChange={setChecked}      />      Preview docs in dark mode {checked ? "(on)" : "(off)"}    </label>  )}

Description

Add a short title and muted description when the choice needs more context.

tsx
import { Checkbox } from "@/components/ui/checkbox"export function Example() {  return (    <label className="flex items-start gap-2.5">      <Checkbox id="watch-tokens" className="mt-0.5" />      <span className="grid gap-1">        <span className="text-sm font-medium tracking-wide">          Watch theme tokens        </span>        <span className="text-sm text-muted-foreground">          Rebuild docs when CSS variables change under globals.css.        </span>      </span>    </label>  )}

Disabled

Set disabled to lock the control. Dim the label as well so the entire row reads as inactive.

tsx
import { Checkbox } from "@/components/ui/checkbox"export function Example() {  return (    <label className="flex items-center gap-2.5 text-sm tracking-wide opacity-60">      <Checkbox disabled id="publish-locked" />      Publish package — unlock after review    </label>  )}

Invalid

Set aria-invalid when validation fails, and use a destructive color for the related label or message.

tsx
import { Checkbox } from "@/components/ui/checkbox"export function Example() {  return (    <label className="flex items-center gap-2.5 text-sm font-medium tracking-wide text-destructive">      <Checkbox id="license" aria-invalid />      Accept the license    </label>  )}

Group

Arrange labeled checkboxes in a list for settings with several independent choices.

Include in the docs build

Pick what ships when you run the registry export.

tsx
import * as React from "react"import { Checkbox } from "@/components/ui/checkbox"const items = [  { id: "docs", label: "Markdown pages" },  { id: "demos", label: "Live demos" },  { id: "tokens", label: "Theme tokens" },  { id: "changelog", label: "Changelog entries" },] as constexport function Example() {  const [selected, setSelected] = React.useState<string[]>(["docs", "demos"])  function toggle(id: string, next: boolean) {    setSelected((prev) =>      next ? [...prev, id] : prev.filter((entry) => entry !== id),    )  }  return (    <div className="grid gap-3">      <div className="grid gap-1">        <p className="text-sm font-medium tracking-wide">          Include in the docs build        </p>        <p className="text-sm text-muted-foreground">          Pick what ships when you run the registry export.        </p>      </div>      <div className="grid gap-2.5">        {items.map((item) => (          <label            key={item.id}            className="flex items-center gap-2.5 text-sm tracking-wide"          >            <Checkbox              id={item.id}              checked={selected.includes(item.id)}              onCheckedChange={(next) => toggle(item.id, next)}            />            {item.label}          </label>        ))}      </div>    </div>  )}

Indeterminate

Set checked="indeterminate" on a parent when only some child options are selected. Selecting the parent checks them all.

tsx
import * as React from "react"import { Checkbox } from "@/components/ui/checkbox"const parts = [  { id: "button", label: "Button" },  { id: "badge", label: "Badge" },  { id: "alert", label: "Alert" },] as constexport function Example() {  const [selected, setSelected] = React.useState<string[]>(["button"])  const allChecked = selected.length === parts.length  const someChecked = selected.length > 0 && !allChecked  function toggleAll(next: boolean) {    setSelected(next ? parts.map((part) => part.id) : [])  }  function toggle(id: string, next: boolean) {    setSelected((prev) =>      next ? [...prev, id] : prev.filter((entry) => entry !== id),    )  }  return (    <div className="grid gap-3">      <label className="flex items-center gap-2.5 text-sm font-medium tracking-wide">        <Checkbox          id="all-parts"          checked={allChecked ? true : someChecked ? "indeterminate" : false}          onCheckedChange={toggleAll}        />        Export UI parts      </label>      <div className="ms-6 grid gap-2.5">        {parts.map((part) => (          <label            key={part.id}            className="flex items-center gap-2.5 text-sm tracking-wide"          >            <Checkbox              id={part.id}              checked={selected.includes(part.id)}              onCheckedChange={(next) => toggle(part.id, next)}            />            {part.label}          </label>        ))}      </div>    </div>  )}

API Reference

Checkbox

PropTypeDefault
checkedboolean | "indeterminate"
defaultCheckedbooleanfalse
onCheckedChange(checked: boolean) => void
disabledbooleanfalse
classNamestring
<Checkbox checked={checked} onCheckedChange={setChecked} />