useCheckbox
Provides the behavior and accessibility implementation for a checkbox component. Checkboxes allow users to select multiple items from a list of individual items, or to mark one individual item as selected.
install | yarn add @react-aria/checkbox |
---|---|
version | 3.0.0-rc.2 |
usage | import {useCheckbox} from '@react-aria/checkbox' |
API#
useCheckbox(
props: AriaCheckboxProps,
state: ToggleState,
inputRef: RefObject<HTMLInputElement>
): CheckboxAria
Features#
Checkboxes can be built with the <input>
HTML element, but this can be difficult to style. useCheckbox
helps achieve accessible checkboxes
that can be styled as needed.
- Built with a native HTML
<input>
element, which can be optionally visually hidden to allow custom styling - Full support for browser features like form autofill
- Keyboard focus management and cross browser normalization
- Labeling support for assistive technology
- Indeterminate state support
Anatomy#
A checkbox consists of a visual selection indicator and a label. Checkboxes support three selection states: checked, unchecked, and indeterminate. Users may click or touch a checkbox to toggle the selection state, or use the Tab key to navigate to it and the Space key to toggle it.
useCheckbox
returns props to be spread onto its input element:
Name | Type | Description |
inputProps | InputHTMLAttributes<HTMLInputElement> | Props for the input element. |
Selection state is managed by the useToggleState
hook in @react-stately/toggle
. The state object should be passed as an option to useCheckbox
.
In most cases, checkboxes should have a visual label. If the checkbox does not have a visible label,
an aria-label
or aria-labelledby
prop must be passed instead to identify the element to assistive
technology.
Example#
import {useToggleState} from '@react-stately/toggle';
function Checkbox(props) {
let {children} = props;
let state = useToggleState(props);
let ref = ReactuseRef();
let {inputProps} = useCheckbox(props state ref);
return (
<label style={display: 'block'}>
<input ...inputProps ref= ref />
children
</label>
);
}
<Checkbox>Test</Checkbox>
<Checkbox isIndeterminate>Test</Checkbox>
import {useToggleState} from '@react-stately/toggle';
function Checkbox(props) {
let {children} = props;
let state = useToggleState(props);
let ref = ReactuseRef();
let {inputProps} = useCheckbox(props state ref);
return (
<label style={display: 'block'}>
<input ...inputProps ref= ref />
children
</label>
);
}
<Checkbox>Test</Checkbox>
<Checkbox isIndeterminate>Test</Checkbox>
import {useToggleState} from '@react-stately/toggle';
function Checkbox(
props
) {
let {children} = props;
let state = useToggleState(
props
);
let ref = ReactuseRef();
let {
inputProps
} = useCheckbox(
props
state
ref
);
return (
<label
style={
display: 'block'
}>
<input
...inputProps
ref= ref
/>
children
</label>
);
}
<Checkbox>
Test
</Checkbox>
<Checkbox
isIndeterminate>
Test
</Checkbox>
Styling#
To build a custom styled checkbox, you can make the native input element visually hidden.
This is possible using the <VisuallyHidden
>
utility component from @react-aria/visually-hidden
. It is still in the DOM and accessible to
assistive technology, but invisible. This example uses SVG to build the visual checkbox,
which is hidden from screen readers with aria-hidden
.
For keyboard accessibility, a focus ring is important to indicate which element has keyboard focus.
This is implemented with the useFocusRing
hook from @react-aria/focus
. When isFocusVisible
is true, an extra SVG element is
rendered to indicate focus. The focus ring is only visible when the user is interacting
with a keyboard, not with a mouse or touch.
import {VisuallyHidden} from '@react-aria/visually-hidden';
import {useFocusRing} from '@react-aria/focus';
function Checkbox(props) {
let {children} = props;
let state = useToggleState(props);
let ref = ReactuseRef();
let {inputProps} = useCheckbox(props state ref);
let {isFocusVisible focusProps} = useFocusRing();
let isChecked = inputPropschecked;
return (
<label style={display: 'flex' alignItems: 'center'}>
<VisuallyHidden>
<input ...inputProps ...focusProps ref= ref />
</VisuallyHidden>
<svg
width=20
height=20
aria-hidden="true"
style={marginRight: 4}>
<rect
x= isChecked ? 4 : 5
y= isChecked ? 4 : 5
width= isChecked ? 12 : 10
height= isChecked ? 12 : 10
fill= isChecked ? 'orange' : 'none'
stroke= isChecked ? 'none' : 'gray'
strokeWidth=2 />
isChecked &&
<path
transform="translate(5 5)"
d=`M3.788 9A.999.999 0 0 1 3 8.615l-2.288-3a1 1 0 1 1
1.576-1.23l1.5 1.991 3.924-4.991a1 1 0 1 1 1.576 1.23l-4.712
6A.999.999 0 0 1 3.788 9z` />
isFocusVisible &&
<rect
x=1
y=1
width=18
height=18
fill="none"
stroke="orange"
strokeWidth=2 />
</svg>
children
</label>
);
}
<Checkbox>Foo</Checkbox>
import {VisuallyHidden} from '@react-aria/visually-hidden';
import {useFocusRing} from '@react-aria/focus';
function Checkbox(props) {
let {children} = props;
let state = useToggleState(props);
let ref = ReactuseRef();
let {inputProps} = useCheckbox(props state ref);
let {isFocusVisible focusProps} = useFocusRing();
let isChecked = inputPropschecked;
return (
<label style={display: 'flex' alignItems: 'center'}>
<VisuallyHidden>
<input ...inputProps ...focusProps ref= ref />
</VisuallyHidden>
<svg
width=20
height=20
aria-hidden="true"
style={marginRight: 4}>
<rect
x= isChecked ? 4 : 5
y= isChecked ? 4 : 5
width= isChecked ? 12 : 10
height= isChecked ? 12 : 10
fill= isChecked ? 'orange' : 'none'
stroke= isChecked ? 'none' : 'gray'
strokeWidth=2
/>
isChecked && (
<path
transform="translate(5 5)"
d=`M3.788 9A.999.999 0 0 1 3 8.615l-2.288-3a1 1 0 1 1
1.576-1.23l1.5 1.991 3.924-4.991a1 1 0 1 1 1.576 1.23l-4.712
6A.999.999 0 0 1 3.788 9z`
/>
)
isFocusVisible && (
<rect
x=1
y=1
width=18
height=18
fill="none"
stroke="orange"
strokeWidth=2
/>
)
</svg>
children
</label>
);
}
<Checkbox>Foo</Checkbox>
import {VisuallyHidden} from '@react-aria/visually-hidden';
import {useFocusRing} from '@react-aria/focus';
function Checkbox(
props
) {
let {children} = props;
let state = useToggleState(
props
);
let ref = ReactuseRef();
let {
inputProps
} = useCheckbox(
props
state
ref
);
let {
isFocusVisible
focusProps
} = useFocusRing();
let isChecked =
inputPropschecked;
return (
<label
style={
display: 'flex'
alignItems:
'center'
}>
<VisuallyHidden>
<input
...inputProps
...focusProps
ref= ref
/>
</VisuallyHidden>
<svg
width=20
height=20
aria-hidden="true"
style={
marginRight: 4
}>
<rect
x=
isChecked
? 4
: 5
y=
isChecked
? 4
: 5
width=
isChecked
? 12
: 10
height=
isChecked
? 12
: 10
fill=
isChecked
? 'orange'
: 'none'
stroke=
isChecked
? 'none'
: 'gray'
strokeWidth=2
/>
isChecked && (
<path
transform="translate(5 5)"
d=`M3.788 9A.999.999 0 0 1 3 8.615l-2.288-3a1 1 0 1 1
1.576-1.23l1.5 1.991 3.924-4.991a1 1 0 1 1 1.576 1.23l-4.712
6A.999.999 0 0 1 3.788 9z`
/>
)
isFocusVisible && (
<rect
x=1
y=1
width=18
height=18
fill="none"
stroke="orange"
strokeWidth=
2
/>
)
</svg>
children
</label>
);
}
<Checkbox>
Foo
</Checkbox>
Internationalization#
RTL#
In right-to-left languages, the checkbox should be mirrored. The checkbox should be placed on the right side of the label. Ensure that your CSS accounts for this.
Name | Type | Description |
isIndeterminate | boolean | Indeterminism is presentational only. The indeterminate visual representation remains regardless of user interaction. |
children | ReactNode | |
defaultSelected | boolean | |
isSelected | boolean | |
onChange | (
(isSelected: boolean
)) => void | |
value | string | |
name | string | |
isDisabled | boolean | Whether the input is disabled. |
isReadOnly | boolean | Whether the input can be selected but not changed by the user. |
validationState | ValidationState | Whether the input should display its "valid" or "invalid" visual styling. |
isRequired | boolean | Whether user input is required on the input before form submission.
Often paired with the necessityIndicator prop to add a visual indicator to the input. |
autoFocus | boolean | Whether the element should receive focus on render |
onFocus | (
(e: FocusEvent
)) => void | Handler that is called when the element receives focus. |
onBlur | (
(e: FocusEvent
)) => void | Handler that is called when the element loses focus. |
onFocusChange | (
(isFocused: boolean
)) => void | Handler that is called when the element's focus status changes. |
onKeyDown | (
(e: KeyboardEvent
)) => void | Handler that is called when a key is pressed. |
onKeyUp | (
(e: KeyboardEvent
)) => void | Handler that is called when a key is released. |
aria-controls | string | Identifies the element (or elements) whose contents or presence are controlled by the current element. |
tabIndex | number | |
id | string | |
aria-label | string | Defines a string value that labels the current element. |
aria-labelledby | string | Identifies the element (or elements) that labels the current element. |
aria-describedby | string | Identifies the element (or elements) that describes the object. |
aria-details | string | Identifies the element (or elements) that provide a detailed, extended description for the object. |
aria-errormessage | string | Identifies the element that provides an error message for the object. |
Name | Type | Description |
isSelected | boolean | Whether the toggle is selected. |
setSelected | (
(isSelected: boolean
)) => void | Updates selection state. |
Name | Type | Description |
inputProps | InputHTMLAttributes<HTMLInputElement> | Props for the input element. |
Provides state management for toggle components like checkboxes and switches.
useToggleState(
(props: CheckboxBase
)): ToggleState
Name | Type | Description |
children | ReactNode | |
defaultSelected | boolean | |
isSelected | boolean | |
onChange | (
(isSelected: boolean
)) => void | |
value | string | |
name | string | |
isDisabled | boolean | Whether the input is disabled. |
isReadOnly | boolean | Whether the input can be selected but not changed by the user. |
validationState | ValidationState | Whether the input should display its "valid" or "invalid" visual styling. |
isRequired | boolean | Whether user input is required on the input before form submission.
Often paired with the necessityIndicator prop to add a visual indicator to the input. |
autoFocus | boolean | Whether the element should receive focus on render |
onFocus | (
(e: FocusEvent
)) => void | Handler that is called when the element receives focus. |
onBlur | (
(e: FocusEvent
)) => void | Handler that is called when the element loses focus. |
onFocusChange | (
(isFocused: boolean
)) => void | Handler that is called when the element's focus status changes. |
onKeyDown | (
(e: KeyboardEvent
)) => void | Handler that is called when a key is pressed. |
onKeyUp | (
(e: KeyboardEvent
)) => void | Handler that is called when a key is released. |
Determines whether a focus ring should be shown to indicate keyboard focus. Focus rings are visible only when the user is interacting with a keyboard, not with a mouse, touch, or other input methods.
useFocusRing(
(props: FocusRingProps
)): FocusRingAria
Name | Type | Description |
within | boolean | Whether to show the focus ring when something inside the container element has focus (true), or only if the container itself has focus (false). |
isTextInput | boolean | Whether the element is a text input. |
autoFocus | boolean | Whether the element will be auto focused. |
Name | Type | Description |
isFocused | boolean | Whether the element is currently focused. |
isFocusVisible | boolean | Whether keyboard focus should be visible. |
focusProps | HTMLAttributes<HTMLElement> | Props to apply to the container element with the focus ring. |