Skip to content
design
Components

Checkbox

Independent choices with named controls, mixed selection, validation and native form values.

On this page
Report sections

Choose the content for this illustrative export.

Included: Executive summary, Classification notice

Choose report sections and use the mixed-state parent to select every editable option.
Code
import { CheckboxGroup, type CheckboxOption } from "@bosunkit/components/checkbox";
import { useState, type Dispatch, type ReactElement, type SetStateAction } from "react";

export const title: string = "Choose the sections of a report";
const options: readonly CheckboxOption[] = [
  {value:"summary",label:"Executive summary",description:"Decisions, outcomes and next priorities."},
  {value:"changes",label:"Engineering changes",description:"Implementation details and supporting evidence."},
  {value:"attachments",label:"Attachments",description:"Supporting documents supplied with the report."},
  {value:"classification",label:"Classification notice",description:"Included in every report.",disabled:true},
];
export default function Example(): ReactElement {
  const [value,setValue]: [readonly string[], Dispatch<SetStateAction<readonly string[]>>] = useState<readonly string[]>(["summary","classification"]);
  return <div>
    <CheckboxGroup label="Report sections" hint="Choose the content for this illustrative export." options={options}
      value={value} onValueChange={setValue} selectAllLabel="Select all optional sections" />
    <p role="status">Included: {options.filter((option: CheckboxOption): boolean => value.includes(option.value)).map((option: CheckboxOption): string => option.label).join(", ")}</p>
  </div>;
}
01Independent choicesEach checkbox answers its own yes-or-no question. Use a radio group when choosing one option excludes the others.
02Visible meaningKeep a visible name beside the mark. Descriptions explain the choice without lengthening its accessible name.
03Honest selectionA mixed mark means some child choices are selected. Selecting a draft option does not confirm that it has been saved.

Single choices and states

Checkbox supports controlled checked and uncontrolled defaultChecked, an independently supplied indeterminate state, required native validation, read-only values and disabled controls. Space changes the focused checkbox; clicking its visible label activates the same control. The full label row meets the shared touch target role. The check and mixed marks distinguish selection without relying on color.

Code
import { Checkbox } from "@bosunkit/components/checkbox";
import type { ReactElement } from "react";
export const title: string = "Unchecked, checked, mixed, read-only and disabled";
export default function Example(): ReactElement {
  return <div>
    <Checkbox label="Include source notes" />
    <Checkbox label="Include figures" defaultChecked />
    <Checkbox label="Some sections selected" indeterminate readOnly hint="The mixed mark describes a partial selection." />
    <Checkbox label="Recorded preference" checked readOnly hint="This value can be read but cannot be changed here." />
    <Checkbox label="Attachment unavailable" disabled hint="Add a supporting document before including it." />
  </div>;
}

Read-only controls retain their value and remain focusable. Disabled controls cannot be changed and do not contribute a value to native form submission. Explain unavailability in a description when the reason helps the reader. Keep links and other buttons outside the checkbox's label.

Grouped choices and select-all

CheckboxGroup takes options and controlled value or uncontrolled defaultValue. Its visible legend names the group. selectAllLabel adds a parent checkbox that derives its checked or mixed state from the enabled options. Select-all changes enabled choices only; disabled selections and values outside the displayed options are preserved. With no enabled choices the parent is disabled.

Use a shared name to submit selected values as repeated form entries. The parent is a convenience control and is not submitted. Uncontrolled groups restore their defaults on form reset. Controlled forms reset through the caller's state. orientation="horizontal" wraps short options rather than squeezing them into one line.

Validation and saving

Code
import { Checkbox } from "@bosunkit/components/checkbox";
import { Button } from "@bosunkit/components/button";
import { useState, type Dispatch, type SubmitEvent, type ReactElement, type SetStateAction } from "react";
export const title: string = "Validation retains the draft";
export default function Example(): ReactElement {
  const [checked,setChecked]: [boolean,Dispatch<SetStateAction<boolean>>] = useState(false);
  const [attempted,setAttempted]: [boolean,Dispatch<SetStateAction<boolean>>] = useState(false);
  const [result,setResult]: [string,Dispatch<SetStateAction<string>>] = useState("");
  function submit(event: SubmitEvent<HTMLFormElement>): void {
    event.preventDefault(); setAttempted(true); setResult(checked ? "Example review confirmed." : "");
  }
  return <form onSubmit={submit} noValidate>
    <Checkbox label="I reviewed the draft" name="reviewed" required checked={checked}
      onCheckedChange={(next: boolean): void => {setChecked(next);setResult("");}}
      error={attempted && !checked ? "Review the draft and select the checkbox to continue." : undefined} />
    <Button type="submit">Confirm review</Button>
    <p role="status">{result}</p>
  </form>;
}

An error is visible, announced and associated with its control or group. Validate minimum or maximum selection counts in the caller; setting required on every checkbox would require every option. A standalone required checkbox is appropriate for an explicit acknowledgment. The example uses application validation to retain and explain an incomplete draft.

The component requests a value change. The application owns saving, pending state, rejection and conflicts. Use inline messages to explain a rejected save and keep the chosen draft.

Do
Make each independent choice explicit.
Don't
Avoid a vague label whose effect depends on nearby prose.

Props

PropTypeDefaultDescription
labelrequiredstring–Visible translated name; keep interactive links outside this label.
hintstring | undefined–Supporting text announced separately from the name.
errorstring | undefined–Validation message; marks the control invalid and describes it.
checkedboolean | undefined–Controlled checked state.
defaultCheckedboolean | undefined–Initial checked state when uncontrolled.
onCheckedChangePrimitive.Root.Props["onCheckedChange"]–Reports a requested change; the caller owns saving.
indeterminateboolean | undefined–Mixed selection, normally derived from child choices.
disabledboolean | undefined–Unavailable and excluded from form submission.
readOnlyboolean | undefined–Focusable and submitted, but cannot be changed.
requiredboolean | undefined–Requires this checkbox before native form submission.
namestring | undefined–Submitted field name.
valuestring | undefined–Submitted checked value; defaults to the native value on.
formstring | undefined–ID of an owning form outside the component's ancestors.
idstring | undefined–Control ID.
classNamestring | undefined–Additional wrapper classes.
testIdstring | undefined–Root test ID; the control uses --control.
refRef<HTMLElement> | undefined–Focusable checkbox element.
PropTypeDefaultDescription
labelrequiredstring–Visible group name.
optionsreadonly CheckboxOption[] | undefined[]Independent choices, each with a unique value.
childrenReactNode–Custom Checkbox children, each carrying its submitted value.
hintstring | undefined–Group instructions.
errorstring | undefined–Group validation message; the caller validates selection counts.
valuereadonly string[] | undefined–Controlled selected values.
defaultValuereadonly string[] | undefinedEMPTYInitially selected values.
onValueChange((value: readonly string[], details: GroupPrimitive.ChangeEventDetails) => void) | undefined–Reports the requested set of selected values.
selectAllLabelstring | undefined–Shows a parent checkbox for all enabled options, using this translated label.
namestring | undefined–Submitted name shared by the child checkboxes.
formstring | undefined–ID of an owning form outside the component's ancestors.
disabledboolean | undefined–Makes every choice unavailable.
readOnlyboolean | undefined–Retains focus and submitted values while preventing edits.
orientation"vertical" | "horizontal" | undefined"vertical"Stacked by default; horizontal choices wrap when needed.
classNamestring | undefined–Additional group classes.
testIdstring | undefined–Root test ID.
refRef<HTMLFieldSetElement> | undefined–Group fieldset.