# Checkbox (/components/forms/checkbox)



Use `Checkbox` when someone can choose an option independently of nearby controls. Pass
`description` to clarify what the option means.

apps/docs/src/examples/checkbox/basic.tsx

```tsx
import { Checkbox } from '@luke-ui/react/checkbox';

export default () => {
	return <Checkbox description="Receive updates by email.">Email notifications</Checkbox>;
};
```

## States [#states]

Use `defaultSelected` for an uncontrolled initial value, or pair `isSelected` with `onChange` when
application state owns the selection. `isIndeterminate` communicates a mixed state, such as a parent
option whose child options are only partly selected.

apps/docs/src/examples/checkbox/states.tsx

```tsx
import { Checkbox } from '@luke-ui/react/checkbox';
import { Comparison, ComparisonItem } from '#docs/comparison';

export default () => {
	return (
		<Comparison direction="vertical">
			<ComparisonItem label="Unchecked">
				<Checkbox>Example checkbox</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Checked">
				<Checkbox defaultSelected>Example checkbox</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Indeterminate">
				<Checkbox isIndeterminate>Example checkbox</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Selected and indeterminate">
				<Checkbox defaultSelected isIndeterminate>
					Example checkbox
				</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Disabled">
				<Checkbox isDisabled>Example checkbox</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Disabled and checked">
				<Checkbox defaultSelected isDisabled>
					Example checkbox
				</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Invalid">
				<Checkbox errorMessage="Select this example checkbox to continue.">
					Example checkbox
				</Checkbox>
			</ComparisonItem>
		</Comparison>
	);
};
```

apps/docs/src/examples/checkbox/controlled.tsx

```tsx
import { Checkbox } from '@luke-ui/react/checkbox';
import { useState } from 'react';

export default () => {
	const [isSelected, setIsSelected] = useState(false);

	return (
		<Checkbox isSelected={isSelected} onChange={setIsSelected}>
			{isSelected ? 'Checked' : 'Unchecked'}
		</Checkbox>
	);
};
```

## Size [#size]

Use `size` to change the checkbox control. It does not change the label typography. `medium` is the
default. Use `small` in compact layouts and `large` where a larger control improves scanning.

apps/docs/src/examples/checkbox/sizes.tsx

```tsx
import { Checkbox } from '@luke-ui/react/checkbox';
import { Comparison, ComparisonItem } from '#docs/comparison';

export default () => {
	return (
		<Comparison direction="vertical">
			<ComparisonItem label="Small">
				<Checkbox defaultSelected size="small">
					Example checkbox
				</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Medium">
				<Checkbox defaultSelected size="medium">
					Example checkbox
				</Checkbox>
			</ComparisonItem>
			<ComparisonItem label="Large">
				<Checkbox defaultSelected size="large">
					Example checkbox
				</Checkbox>
			</ComparisonItem>
		</Comparison>
	);
};
```

## Validation [#validation]

Set `isRequired` to require the choice. `Checkbox` shows its validation message after validation
fails. Pass `errorMessage` only for an error you already have, such as one from a form library or
your server. A non-empty message marks the checkbox invalid. Read [Validation](/docs/validation) for
where messages come from and how to write them.

apps/docs/src/examples/checkbox/validation.tsx

```tsx
import { Box } from '@luke-ui/react/box';
import { Button } from '@luke-ui/react/button';
import { Checkbox } from '@luke-ui/react/checkbox';
import type { SubmitEvent } from 'react';

export default () => {
	function handleSubmit(event: SubmitEvent<HTMLFormElement>) {
		event.preventDefault();
	}

	return (
		<form onSubmit={handleSubmit}>
			<Box display="flex" flexDirection="column" gap="sp16" maxInlineSize="20rem">
				<Checkbox description="We record the date you accepted." isRequired>
					I accept the terms of service
				</Checkbox>
				<Box>
					<Button type="submit">Create account</Button>
				</Box>
			</Box>
		</form>
	);
};
```

## Labels with Text [#labels-with-text]

Wrap a checkbox in block `Text` when its label needs a specific text size. The control follows the
inherited line height. It keeps its fixed visual square centred on the first line when the label
wraps. Outside `Text`, it uses the normal compact control size.

apps/docs/src/examples/checkbox/first-line-alignment.tsx

```tsx
import { Box } from '@luke-ui/react/box';
import { Checkbox } from '@luke-ui/react/checkbox';
import { Text } from '@luke-ui/react/text';

export default () => {
	return (
		<Box display="grid" gap="sp16" maxInlineSize="18rem">
			<Text elementType="div" typography="caption">
				<Checkbox>A longer label keeps its control aligned when it wraps.</Checkbox>
			</Text>
			<Text elementType="div" typography="heading4">
				<Checkbox>Larger text keeps the same first-line alignment when it wraps.</Checkbox>
			</Text>
		</Box>
	);
};
```

## Accessibility [#accessibility]

Pass a visible label as `Checkbox` children. Use `aria-label` only when surrounding content already
names the control.

Disabled checkboxes cannot receive focus, and their value cannot change. Read-only checkboxes remain
focusable, so someone who uses a keyboard or assistive technology can still perceive their state.
Keyboard navigation shows a focus ring. Pointer focus does not.

## Related components [#related-components]

Use the [Checkbox primitive](/components/primitives/checkbox) to arrange the clickable content,
control, indicator, description, and error slots yourself.

## API [#api]

<ComponentPropsTable
  id="type-table-checkbox.tsx-CheckboxProps"
  type="{
  &#x22;id&#x22;: &#x22;checkbox.tsx-CheckboxProps&#x22;,
  &#x22;name&#x22;: &#x22;CheckboxProps&#x22;,
  &#x22;description&#x22;: &#x22;Props for `Checkbox`.&#x22;,
  &#x22;entries&#x22;: [
    {
      &#x22;name&#x22;: &#x22;children&#x22;,
      &#x22;description&#x22;: &#x22;Checkbox label content.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;ReactNode&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;ReactNode&#x22;,
      &#x22;required&#x22;: true,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;defaultSelected&#x22;,
      &#x22;description&#x22;: &#x22;Initial selection state for an uncontrolled checkbox.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;description&#x22;,
      &#x22;description&#x22;: &#x22;Supporting text shown beneath the checkbox label.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;ReactNode&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;ReactNode&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;errorMessage&#x22;,
      &#x22;description&#x22;: &#x22;Validation message for a controlled error. A non-empty message marks the field invalid.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;ReactNode&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;ReactNode&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;inputRef&#x22;,
      &#x22;description&#x22;: &#x22;Forwarded to the underlying `<input type=\&#x22;checkbox\&#x22;>` element.\n\nThis field takes no plain `ref`: `inputRef` is the only way to reach the\ncontrol, so a ref can never silently resolve to a wrapper element instead.\n\nWidened from React Aria's own `inputRef`, which only takes a ref object, so a\ncallback ref (what form libraries hand out) is accepted too.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;Ref<HTMLInputElement> | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;isDisabled&#x22;,
      &#x22;description&#x22;: &#x22;Whether the checkbox is disabled.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;isIndeterminate&#x22;,
      &#x22;description&#x22;: &#x22;Whether the checkbox displays a mixed selection state.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;isReadOnly&#x22;,
      &#x22;description&#x22;: &#x22;Whether the checkbox can be read but not changed.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;isRequired&#x22;,
      &#x22;description&#x22;: &#x22;Whether the checkbox is required before the form can submit.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;isSelected&#x22;,
      &#x22;description&#x22;: &#x22;Whether the checkbox is selected.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onChange&#x22;,
      &#x22;description&#x22;: &#x22;Called when the selection changes.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((isSelected: boolean) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;size&#x22;,
      &#x22;description&#x22;: &#x22;Visual size of the checkbox control.&#x22;,
      &#x22;tags&#x22;: [
        {
          &#x22;name&#x22;: &#x22;default&#x22;,
          &#x22;text&#x22;: &#x22;'medium'&#x22;
        }
      ],
      &#x22;type&#x22;: &#x22;\&#x22;medium\&#x22; | \&#x22;large\&#x22; | \&#x22;small\&#x22; | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;validationBehavior&#x22;,
      &#x22;description&#x22;: &#x22;Whether to use native HTML form validation to prevent form submission\nwhen the value is missing or invalid, or mark the field as required\nor invalid via ARIA.&#x22;,
      &#x22;tags&#x22;: [
        {
          &#x22;name&#x22;: &#x22;default&#x22;,
          &#x22;text&#x22;: &#x22;'native'&#x22;
        }
      ],
      &#x22;type&#x22;: &#x22;\&#x22;native\&#x22; | \&#x22;aria\&#x22; | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;validate&#x22;,
      &#x22;description&#x22;: &#x22;A function that returns an error message if a given value is invalid.\nValidation errors are displayed to the user when the form is submitted\nif `validationBehavior=\&#x22;native\&#x22;`. For realtime validation, use the `isInvalid`\nprop instead.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((value: boolean) => ValidationError | true | null | undefined) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;autoFocus&#x22;,
      &#x22;description&#x22;: &#x22;Whether the element should receive focus on render.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;boolean | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onFocus&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when the element receives focus.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: React.FocusEvent<Element, Element>) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onBlur&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when the element loses focus.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: React.FocusEvent<Element, Element>) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onFocusChange&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when the element's focus status changes.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((isFocused: boolean) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onKeyDown&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when a key is pressed.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: KeyboardEvent) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onKeyUp&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when a key is released.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: KeyboardEvent) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;id&#x22;,
      &#x22;description&#x22;: &#x22;The element's unique identifier. See\n[MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id).&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;string&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;aria-label&#x22;,
      &#x22;description&#x22;: &#x22;Defines a string value that labels the current element.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;string&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;aria-labelledby&#x22;,
      &#x22;description&#x22;: &#x22;Identifies the element (or elements) that labels the current element.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;string&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;aria-describedby&#x22;,
      &#x22;description&#x22;: &#x22;Identifies the element (or elements) that describes the object.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;string&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;aria-details&#x22;,
      &#x22;description&#x22;: &#x22;Identifies the element (or elements) that provide a detailed, extended description for the\nobject.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;string&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;aria-errormessage&#x22;,
      &#x22;description&#x22;: &#x22;Identifies the element that provides an error message for the object.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;string&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onPress&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when the press is released over the target.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: PressEvent) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onPressStart&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when a press interaction starts.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: PressEvent) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onPressEnd&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when a press interaction ends, either\nover the target or when the pointer leaves the target.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: PressEvent) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onPressChange&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when the press state changes.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((isPressed: boolean) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;onPressUp&#x22;,
      &#x22;description&#x22;: &#x22;Handler that is called when a press is released over the target, regardless of\nwhether it started on the target or not.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;((e: PressEvent) => void) | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;function&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;render&#x22;,
      &#x22;description&#x22;: &#x22;Overrides the default DOM element with a custom render function.\nThis allows rendering existing components with built-in styles and behaviors\nsuch as router links, animation libraries, and pre-styled components.\n\nRequirements:\n\n- You must render the expected element type (e.g. if `<button>` is expected, you cannot render an\n  `<a>`).\n- Only a single root DOM element can be rendered (no fragments).\n- You must pass through props and ref to the underlying DOM element, merging with your own prop\n  as appropriate.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;DOMRenderFunction<\&#x22;div\&#x22;, CheckboxFieldRenderProps> | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;DOMRenderFunction<\&#x22;div\&#x22;, object>&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;name&#x22;: &#x22;slot&#x22;,
      &#x22;description&#x22;: &#x22;A slot name for the component. Slots allow the component to receive props from a parent\ncomponent. An explicit `null` value indicates that the local props completely override all\nprops received from a parent.&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;string | null | undefined&#x22;,
      &#x22;simplifiedType&#x22;: &#x22;union&#x22;,
      &#x22;required&#x22;: false,
      &#x22;deprecated&#x22;: false
    },
    {
      &#x22;deprecated&#x22;: false,
      &#x22;description&#x22;: &#x22;`CheckboxProps` also accepts compatible DOM and ARIA attributes and event handlers for its rendered element.&#x22;,
      &#x22;name&#x22;: &#x22;__nativePropsForwarding&#x22;,
      &#x22;required&#x22;: true,
      &#x22;simplifiedType&#x22;: &#x22;&#x22;,
      &#x22;tags&#x22;: [],
      &#x22;type&#x22;: &#x22;&#x22;
    }
  ]
}"
/>
