v0.5

Checkbox Group

Labelled checkbox row that pairs a single Checkbox with a label, description, and error footer.

Get a digest of product updates once a week.

Description

CheckboxGroup is a horizontal form-field row: one Checkbox, one label/description block, and an optional footer for error or helper text. It cascades variant, size, and shape to the child Checkbox through CheckboxContext so you only configure those properties once.

Reach for it when a single boolean needs a real label: settings panels, consent rows, opt-in toggles inside multi-step forms. For multi-select lists, stack several CheckboxGroup rows inside a FieldSet with a shared FieldLegend; the cascade keeps every child visually aligned without per-row prop drilling.

Don't use it for one-of-many selection; that's RadioGroup. Don't use it for a bare unlabelled checkbox in a table row or toolbar; drop down to Checkbox directly to avoid the layout cost of Field.

Installation

pnpm dlx @create-ui/cli add checkbox-group

Anatomy

CheckboxGroup composes Field around one Checkbox and its label content. The label block lives inside FieldContent so description and footer slots stay aligned with the checkbox's first line.

<CheckboxGroup>
  <Checkbox id="…" />
  <FieldContent>
    <LabelMain>
      <Label htmlFor="…" />
      <LabelDescription />
    </LabelMain>
    <FieldFooter />
  </FieldContent>
</CheckboxGroup>

Usage

import { Checkbox } from "@/components/ui/checkbox"
import { CheckboxGroup } from "@/components/ui/checkbox-group"
import { Label } from "@/components/ui/label"
<CheckboxGroup>
  <Checkbox id="agree" />
  <Label htmlFor="agree">I agree to the terms</Label>
</CheckboxGroup>

Examples

Variants

variant="primary" is the default. variant="danger" repaints the description and footer in text-error-base and forwards invalid to the underlying Field, which sets aria-invalid on its descendants.

We'll only send the things you ask for.

You must agree to the terms before continuing.

Required field.

Sizes

size controls both the checkbox box and the label scale through Field and Label context. Pick xs for dense settings tables and md when the row stands alone in a form.

Checkbox and label scale together from the group.

Checkbox and label scale together from the group.

Checkbox and label scale together from the group.

Placement

placement="left" (default) puts the checkbox before the label. placement="right" flips the row direction without changing the DOM order, which is useful when aligning checkboxes against a right-hand edge.

Default — checkbox before label.

Mirror layout — checkbox after label.

Shapes

shape cascades to the child Checkbox so the visual treatment stays consistent across every row in a group.

Shape cascades from the group to the child checkbox.

Shape cascades from the group to the child checkbox.

Shape cascades from the group to the child checkbox.

Disabled

disabled on the group sets the Field context's disabled flag, which fades the label and description and prevents pointer events on the row. Pass disabled on the child Checkbox too if you also need to remove it from the tab order.

Disabled state cascades to the label and description.

Accessibility

CheckboxGroup delegates all focus and ARIA behavior to its children; the wrapping Field is a role="group" div, not an input. Keyboard interaction lives on the child Checkbox.

KeyDescription
SpaceToggles the checked state of the focused child checkbox.
TabMoves focus to the next focusable element.

ARIA notes:

  • The root <div> is role="group" and exposes data-invalid, data-disabled, and data-loading so descendants (label, description, footer) restyle through Tailwind group selectors.
  • Setting invalid cascades through Field so descendants pick up aria-invalid styling.
  • Always associate the child Checkbox id with the Label htmlFor so screen readers announce the row's purpose.

Styling

Tailwind override: pass className to merge Tailwind classes on the root row:

<CheckboxGroup className="w-[340px]" />

Data slots and attributes: the component sets these for CSS targeting:

  • data-slot="checkbox-group" on the root.
  • data-variant="<variant>", data-placement="<placement>", data-shape="<shape>" on the root.
  • Inherited from Field: data-slot="field", data-size, data-orientation="horizontal", data-invalid, data-disabled, data-loading.
  • variant="danger" restyles [data-slot="field-footer"] (and any nested <a>) to text-error-base.

Target the error state in CSS:

[data-slot="checkbox-group"][data-variant="danger"] [data-slot="field-footer"] {
  color: var(--color-error-base);
}
  • Checkbox: the bare primitive without label/footer; use directly inside dense rows.
  • RadioGroup: single-select alternative.
  • Field: the lower-level form-field wrapper this component composes; reach for it when you need a different layout.

API Reference

CheckboxGroup

A horizontal Field that wraps one Checkbox plus its label content. Extends React.ComponentProps<typeof Field> minus the orientation and size props (which are managed internally).

Props

PropTypeDefaultDescription
childrenReact.ReactNode-The Checkbox plus its label content (typically inside FieldContent).
disabledboolean-Disables interaction and cascades a disabled style to label, description, and footer.
invalidboolean-Marks the row as invalid; cascades aria-invalid styling through Field.
loadingboolean-Forwarded to Field; useful for skeleton/spinner states.
classNamestring-Tailwind classes merged with the component's CVA classes on the root.

Variants

VariantOptionsDefaultDescription
variant"primary" "danger""primary"Semantic intent. "danger" cascades to the child checkbox and restyles the footer.
size"xs" "sm" "md""md"Cascades to the child checkbox and label via context.
shape"rounded" "pill" "square""rounded"Cascades to the child checkbox.
placement"left" "right""left"Row direction. "right" flips the visual order while preserving DOM order.