Skip to content

Checkbox

Checkbox and CheckboxGroup work together to build checkbox form fields.
Figma logo
  • CheckboxGroup is a field element that wraps checkboxes with label, helper, and validation text.
  • Validation text must be added separately when using Checkbox on its own (example).
Switch
  • Switch reflects a boolean state (enabled/disabled, on/off)
  • Switch has a more approachable UI that users may associate with an immediate response
Checkbox
  • A single Checkbox should be used when agreeing/acknowledging/accepting terms/policies, etc.
  • Typically associated with a form that must be submitted for changes to be saved/reflected
  • Checkbox is used when multiple items can be selected
  • Only used to change settings, not as a trigger
    • Use Button if you need to perform an action
Radio
  • Use Radio if you need to toggle between two non-binary options (e.g. CSV/PDF, %/$)
  • Typically associated with a form that must be submitted for changes to be saved/reflected
  • Radio is used when the options are mutually exclusive
  • Only used to change settings, not as a trigger
    • Use Button if you need to perform an action

A basic CheckboxGroup implementation using Formik and Yup to require the field.

A CheckboxGroup implementation using Formik and Yup to require at least one box be selected. Child content is treated as helper text.

This example illustrates using Checkbox without CheckboxGroup. This method is far more laborious as validation text must be added manually.

A checkbox can have an indeterminate state when its value cannot be expressed with a binary true or false value. This state is most often used on groups of checkboxes that contain “children” elements, which can have different values.

Disabled states should be used with caution.

It may sometimes be necessary to hide labels, but label text must still be made available for screen readers. This example uses visuallyHidden to visually hide the label.

React props
NameTypeDefaultDescription
children  RequiredReactNodeThe individual Checkbox elements that are part of the group.
disabled  booleanIf true, the elements in this group will be shown in their disabled state.
helperText  ReactNodeAdditional descriptive information for the checkboxes.
invalid  booleanIf true, the checkboxes will be shown in their invalid state.
label  RequiredstringLabel text associated with the input.
name  stringName of the input. Submitted with the form as part of a name/value pair.
optionalText  stringText used to indicate that a field is not required.
validationText  ReactNodeValidation message associated with the input.
React props
NameTypeDefaultDescription
children  ReactNodeContent will be treated as helper text.
component  ReactNodeComponent override for the <input> element.
indeterminate  booleanIf true, the checkbox will be displayed in an indeterminate state.
label  RequiredstringLabel text associated with the input.
value  RequiredstringThe data value of the input.

The following testing snippet(s) offer suggestions for testing the component using React Testing Library with occasional help from Jest.

render(
<CheckboxGroup
name="notifications"
label="Enable notifications?"
optionalText="(optional)"
helperText="How much would you like to hear from us?"
>
<Checkbox label="Alerts" value="alerts">
Alerts are like really really important things that we only tell you about when the world is
ending.
</Checkbox>
<Checkbox label="Newsletter" value="newsletter">
This is pretty much just everything else.
</Checkbox>
</CheckboxGroup>,
);
const group = screen.getByRole('group', {
name: 'Enable notifications?', // Group label
});
// Group descriptions
expect(group).toHaveAccessibleDescription(expect.stringContaining('(optional)'));
expect(group).toHaveAccessibleDescription(
expect.stringContaining('How much would you like to hear from us?'),
);
const alertsCheckbox = screen.getByLabelText('Alerts');
// Alternatively:
// const alertsCheckbox = screen.getByRole('checkbox', {
// name: 'Alerts',
// });
// Checkbox description
expect(alertsCheckbox).not.toBeChecked();
expect(alertsCheckbox).toHaveAccessibleDescription(
'Alerts are like really really important things that we only tell you about when the world is ending.',
);
const newsletterCheckbox = screen.getByLabelText('Newsletter');
// Checkbox description
expect(newsletterCheckbox).not.toBeChecked();
expect(newsletterCheckbox).toHaveAccessibleDescription('This is pretty much just everything else.');
// Checking
userEvent.click(alertsCheckbox);
expect(alertsCheckbox).toBeChecked();
// Testing validation
render(
<CheckboxGroup
name="notifications"
label="Enable notifications?"
invalid
validationText="At least one selection is required"
>
<Checkbox label="Alerts" value="alerts" />
<Checkbox label="Newsletter" value="newsletter" />
</CheckboxGroup>,
);
const group = screen.getByRole('group', {
name: 'Enable notifications?', // Group label
});
expect(group).toHaveAccessibleDescription(
expect.stringContaining('At least one selection is required'),
);