Checkbox
The Checkbox component is a styled control for boolean fields. It wraps Base UI's checkbox, so it works with Field and React Hook Form the same way Input, Select, and Combobox do — dropped inside a Field.Root it inherits label association, aria-describedby, disabled, and the invalid (error) state automatically.
Import
import { Checkbox } from "@tailor-platform/app-shell";Basic Usage
<Checkbox label="Subscribe to updates" />Omit label to render just the box — useful for a table row-select cell (pass aria-label) or when a Field.Label sibling supplies the text.
<Checkbox aria-label="Select row" />Props
Accepts all Base UI Checkbox.Root props, plus label. The most common:
| Prop | Type | Default | Description |
|---|---|---|---|
label | React.ReactNode | - | Inline label rendered next to the box (wraps both in a <label>). Omit for box-only. |
checked | boolean | - | Controlled checked state. |
defaultChecked | boolean | false | Initial checked state when uncontrolled. |
onCheckedChange | (checked: boolean, details) => void | - | Called with the next boolean state. |
indeterminate | boolean | false | Renders the "partially selected" (mixed) state. |
disabled | boolean | false | Disables the control. |
required | boolean | false | Marks the control as required for native/Field validation. |
name | string | - | Field name for native form submission. |
value | string | - | Submitted value when checked (native forms). |
inputRef | React.Ref<HTMLInputElement> | - | Ref to the hidden native input (use for React Hook Form's field.ref). |
className | string | - | Applied to the outer element — the <label> when label is set, else the box. |
Examples
Controlled
const [checked, setChecked] = useState(false);
<Checkbox label="Enable notifications" checked={checked} onCheckedChange={setChecked} />;Indeterminate ("select all")
<Checkbox
aria-label="Select all rows"
checked={allSelected}
indeterminate={someSelected && !allSelected}
onCheckedChange={(checked) => (checked ? selectAll() : clearAll())}
/>Disabled
<Checkbox label="Unavailable option" disabled />Use With Field
Placed inside a Field.Root, Checkbox picks up the field's invalid and disabled state automatically — no error prop of its own. Use the inline label for the checkbox text and Field.Error for the message below it.
<Field.Root name="acceptTerms" error={{ message: "You must accept the terms." }}>
<Checkbox label="I accept the terms and conditions" />
<Field.Error>You must accept the terms.</Field.Error>
</Field.Root>React Hook Form
Drive the checkbox with a Controller. onCheckedChange hands React Hook Form a boolean directly, and spreading fieldState onto Field.Root wires the error/invalid state.
import { useForm, Controller } from "react-hook-form";
function TermsForm() {
const { control, handleSubmit } = useForm({ defaultValues: { acceptTerms: false } });
return (
<Form onSubmit={handleSubmit((data) => save(data))}>
<Controller
name="acceptTerms"
control={control}
rules={{ required: "You must accept the terms." }}
render={({ field, fieldState }) => (
<Field.Root name={field.name} {...fieldState}>
<Checkbox
label="I accept the terms and conditions"
checked={field.value}
onCheckedChange={field.onChange}
onBlur={field.onBlur}
inputRef={field.ref}
/>
<Field.Error>{fieldState.error?.message}</Field.Error>
</Field.Root>
)}
/>
<button type="submit">Save</button>
</Form>
);
}With a shadcn-style FormField
Checkbox also drops into the common shadcn FormField / FormControl / FormMessage pattern — no AppShell Field needed. FormControl injects id, aria-describedby, and aria-invalid onto the control; Checkbox forwards them (and ref, in React 19) to the underlying element and styles its error state off aria-invalid, so the invalid highlight works here too.
<FormField
control={control}
name="acceptTerms"
render={({ field }) => (
<FormItem>
<FormControl>
<Checkbox
label="I accept the terms and conditions"
checked={field.value}
onCheckedChange={field.onChange}
onBlur={field.onBlur}
inputRef={field.ref}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>Use the inline
labelprop for the checkbox text (it wraps the box in a<label>, so clicking the text toggles it). A separateFormLabelwithhtmlForis descriptive only — the control renders a<span role="checkbox">, which isn't a natively labelable element, so a sibling label won't toggle it on click.
TypeScript
import { type CheckboxProps } from "@tailor-platform/app-shell";Related Components
- Form, Field, and Fieldset — Checkbox integrates with
Fieldfor labels, errors, and validation. - Input — Text input counterpart.