Checkbox

Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.

Updated in eds-core: 1.12.0

Quick Start

Installation
npm install @adaptavant/eds-core
Import
import { Checkbox } from '@adaptavant/eds-core';

Size

Customise the size of the Checkbox via the size prop.

{/* large */}
<Checkbox label="Check me!" size="large" />

{/* standard */}
<Checkbox label="Check me!" size="standard" />

Disabled

Use the isDisabled prop to show that a Checkbox isn't usable.

<Checkbox isDisabled label="Check me!" />

Invalid

Use the errorMessage prop to show that a Checkbox has an error associated with it.

<Checkbox errorMessage="Invalid selection" label="Check me!" />

Controlled

A controlled Checkbox component uses React’s state and a callback function to update the state.

Status: Unchecked ❌
  const [selected, setSelected] = React.useState(false);
  const handleChange = (e) => setSelected(e.target.checked);

  return (
    <Stack>
      <Checkbox label="Check me!" onChange={handleChange} />
      <Text className="text-body-12"> Status: {selected ? "Checked ✅  " : "Unchecked ❌"}</Text>
    </Stack>
  );

Uncontrolled

An uncontrolled Checkbox component uses ref prop to access the current selected state. Additionally, you can maintain a React state to update other UI elements if needed.

Status: Checked ✅
  const checkboxRef = React.useRef(null);
  const [selected, setSelected] = React.useState(true);
  const handleChange = () => {
    if (checkboxRef.current) {
      setSelected(checkboxRef.current.checked);
    }
  };
  const handleClick = () => {
      alert(`My value is: "${checkboxRef.current.checked}"`);
  };

  return (
    <Stack className="gap-2">
      <Checkbox defaultChecked={true} label="Check me!" onChange={handleChange} ref={checkboxRef} />
      <Text className="text-body-12"> Status: {selected ? "Checked ✅  " : "Unchecked ❌"} </Text>
      <Button onClick={handleClick}>Click me!</Button>
    </Stack>
);

Indeterminate

The Checkbox component includes an indeterminate prop, designed for scenarios like header groups where some, but not all, options are selected. This is particularly useful for select-all checkboxes in group headers, as it visually indicates a partially selected state when only a subset of items is checked.

  const [checkedItems, setCheckedItems] = React.useState({
    1: true, // By default checked (makes header checkbox render in indeterminate state)
    2: false,
    3: false,
    4: false,
  });

  const [headerDisabled, setHeaderDisabled] = React.useState(false); // toggle this to make header checkbox disabled

  const disabledItems = {
			1: false,
			2: true, // By default disabled checkbox sub-item
			3: false,
      4: false,
		};

  const enabledItems = Object.keys(checkedItems).filter(
    (key) => !disabledItems[key]
  );

  const allChecked = enabledItems.every((key) => checkedItems[key]);
  const someChecked = enabledItems.some((key) => checkedItems[key]) && !allChecked;

  const handleHeaderChange = () => {
    const newCheckedState = !allChecked;
    setCheckedItems((prevState) => {
      const updatedState = { ...prevState };
      enabledItems.forEach((key) => {
        updatedState[key] = newCheckedState;
      });
      return updatedState;
    });
  };

  const handleItemChange = (id) => {
    setCheckedItems((prevState) => ({
      ...prevState,
      [id]: !prevState[id],
    }));
  };

  return (
    <Stack className="gap-2">
				<Checkbox
					checked={allChecked}
          isDisabled={headerDisabled}
					indeterminate={someChecked} // Visually indicates a partially selected state
					label="Select all"
					onChange={handleHeaderChange}
				/>
				<Stack className="pl-5">
					<Checkbox
						checked={checkedItems['1']}
						id="1"
            isDisabled={headerDisabled || disabledItems['1']} // When header is disabled, all sub-items should disabled
						label="Item 1"
						onChange={() => handleItemChange('1')}
					/>
					<Checkbox
						checked={checkedItems['2']}
						id="2"
            isDisabled={headerDisabled || disabledItems['2']} // By default disabled (header checkbox should not consider this for allchecked/somechecked state)
						label="Item 2"
						onChange={() => handleItemChange('2')}
					/>
					<Checkbox
						checked={checkedItems['3']}
						id="3"
            isDisabled={headerDisabled || disabledItems['3']}
						label="Item 3"
						onChange={() => handleItemChange('3')} // Ensure "id" is passed to handleItemChange
					/>
          <Checkbox
						checked={checkedItems['4']}
						id="4"
            isDisabled={headerDisabled || disabledItems['3']}
						label="Item 4"
						onChange={() => handleItemChange('4')}
					/>
				</Stack>
			</Stack>
);

Note: This is purely a visual change. It has no impact on whether the checkbox's value is used in a form submission. That is decided by the checked state, regardless of the indeterminate state.

Style API

Our design system components include style props that allow you to easily customize different parts of each component to match your design needs.

Please refer to the Style API documentation for more insights.

Checkbox parts

Please enter a guide description
{/* Styling the label and description parts */}
<Checkbox
  label="Control Text Label"
  size="large"
  description="Please enter a guide description"
  className="bg-neutral-secondary"
  classNames={{
    checkboxPrimitiveControl: "bg-critical hover:bg-critical-hover",
    checkboxPrimitiveIcon: "bg-accent",
    label: "text-body-14 text-tertiary",
    descriptionTrack: "gap-1 ",
    description: "text-positive",
    spacer: "h-8",
  }}
/>

{/* Styling the error parts */}
<Checkbox
  label="Control Text Label"
  size="large"
  errorMessage="Error message goes here"
  classNames={{
    errorTrack: "text-caution",
    errorIcon: "text-caution",
    errorMessage: "text-caution",
  }}
/>

Stylable Parts

Description

root

The root container of the checkbox, wrapping all inner components.

checkboxPrimitiveRoot

The base container for the primitive checkbox structure.

checkboxPrimitiveInput

The input element for the checkbox, where the value is stored.

checkboxPrimitiveControl

The container for the control element, which visually represents the checked/unchecked state.

checkboxPrimitiveIcon

The icon displayed within the checkbox when it is checked.

label

The text label associated with the checkbox.

descriptionTrack

Wrapper for the description text when it appears alongside the checkbox.

description

Description text providing additional information about the checkbox.

spacer

A spacer element used to create a gap between the description text and the start of the description track to maintain alignment for description text and label.

errorTrack

The container for error messages when the checkbox is invalid.

errorIcon

Icon displayed to indicate an error state, typically styled to match the error message.

errorMessage

Text of the error message, providing feedback when validation fails.

Usage guidelines

Do

  • List, form, or table selections: Utilize checkboxes in lists, forms, or tables to present users with multiple, related options where selecting all, none, or some choices is necessary.
  • Accompanying field and InlineField components: Include checkboxes in forms alongside field and InlineField components or in constrained spaces where a toggle might be impractical due to size limitations.
  • Non-immediate selections: Opt for checkboxes when the user's selection does not take immediate effect and requires submission of a form for changes to occur.

Don’t

  • Exclusive choices: Avoid checkboxes in situations where users can only choose one option out of multiple, related choices. Instead, use a RadioGroup to enforce exclusivity.
  • Immediate selections, especially on mobile: Refrain from using checkboxes when a selection needs to take immediate effect, particularly in mobile contexts. Instead, employ a toggle for swift and direct interactions.
  • Ambiguous visual feedback: Steer clear of checkboxes when the visual distinction between turning a feature on or off is unclear. In such cases, a Toggle is recommended for its clarity in indicating the on/off state.

Best practices

Do

checkbox1

Employ checkboxes to enable the multi-selection of interconnected list items.

Don’t

checkbox2

Opt for checkboxes when allowing for a single selection is required. Alternatively, use a RadioGroup for this purpose.

Do

checkbox3

In forms where the selection becomes effective only after submitting, utilize a singular checkbox.

Don’t

checkbox4

Utilize a Checkbox for instant toggling of a state. Alternatively, use a Toggle for this purpose.

Do

checkbox5

Maintain concise and clear labels, legends and descriptions to prevent an overload of text that may impede scanning and slow down the user.

Don’t

checkbox6

Avoid using extensive text that gets truncated or fails to provide clear instructions on the expected selection.