Checkbox
import {Checkbox} from "@qualcomm-ui/react/checkbox"Examples
Simple
The simple API provides a standalone component with built-in layout.
<Checkbox label="Checkbox" />Composite
Build with the composite API for granular control. This API requires you to provide each subcomponent, but gives you full control over the structure and layout.
<Checkbox.Root>
<Checkbox.HiddenInput />
<Checkbox.Label>Label</Checkbox.Label>
<Checkbox.Control />
</Checkbox.Root>States
Based on the inputs, the checkbox will render as checked, indeterminate, or unchecked (default). The checked state takes precedence over indeterminate.
| checked | indeterminate | Result State |
|---|---|---|
false | false | |
false | true | |
true | false | |
true | true |
<Checkbox defaultChecked label="Label" />
<Checkbox label="Label" />
<Checkbox indeterminate label="Label" />Disabled State
When disabled is true, the checkbox becomes non-interactive and is typically rendered with reduced opacity to indicate its unavailable state.
<Checkbox defaultChecked disabled label="Label" />
<Checkbox disabled label="Label" />
<Checkbox disabled indeterminate label="Label" />Controlled State
Set the initial value using the defaultChecked prop, or use checked and onCheckedChange to control the value manually. These props follow our controlled state pattern.
import {type ReactElement, useState} from "react"
import {Checkbox} from "@qualcomm-ui/react/checkbox"
export default function CheckboxControlledDemo(): ReactElement {
const [checked, setChecked] = useState<boolean>(false)
return (
<Checkbox.Root
checked={checked}
onCheckedChange={(nextState) => {
console.log("checkbox state change:", nextState)
setChecked(nextState)
}}
>
<Checkbox.HiddenInput />
<Checkbox.Control />
<Checkbox.Label>Label</Checkbox.Label>
</Checkbox.Root>
)
}
Sizes
import type {ReactElement} from "react"
import {Checkbox} from "@qualcomm-ui/react/checkbox"
export default function CheckboxSizesDemo(): ReactElement {
return (
<div className="flex flex-col items-start gap-4">
<Checkbox label="Small (sm)" size="sm" />
<Checkbox label="Medium (md)" size="md" />
<Checkbox label="Large (lg)" size="lg" />
</div>
)
}
Forms
Choose the form library that fits your needs—we've built examples with React Hook Form and Tanstack Form to get you started.
React Hook Form
Use React Hook Form to handle the checkbox state and validation. ArkType works great for schema validation if you need it.
import type {ReactElement} from "react"
import {arktypeResolver} from "@hookform/resolvers/arktype"
import {type} from "arktype"
import {Controller, useForm} from "react-hook-form"
import {Button} from "@qualcomm-ui/react/button"
import {Checkbox} from "@qualcomm-ui/react/checkbox"
interface FormData {
acceptTerms: boolean
newsletter: boolean
}
const acceptTermsSchema = type("boolean")
.narrow((value: boolean) => value === true)
.configure({
message: "Please accept the Terms of Service to continue",
})
const FormSchema = type({
// must be true
acceptTerms: acceptTermsSchema,
// can be true or false
newsletter: "boolean",
})
export default function CheckboxReactHookFormDemo(): ReactElement {
const {control, handleSubmit} = useForm<FormData>({
defaultValues: {
acceptTerms: false,
newsletter: true,
},
resolver: arktypeResolver(FormSchema),
})
return (
<form
className="flex w-56 flex-col gap-2"
onSubmit={(e) => {
void handleSubmit((data) => console.log(data))(e)
}}
>
<Controller
control={control}
name="newsletter"
render={({field: {name, onChange, value, ...fieldProps}}) => {
return (
<Checkbox.Root
checked={value}
name={name}
onCheckedChange={onChange}
{...fieldProps}
>
<Checkbox.HiddenInput />
<Checkbox.Control />
<Checkbox.Label>Subscribe to our Newsletter</Checkbox.Label>
</Checkbox.Root>
)
}}
/>
<Controller
control={control}
name="acceptTerms"
render={({
field: {onChange, value, ...fieldProps},
fieldState: {error},
}) => {
return (
<Checkbox.Root
checked={value}
invalid={!!error?.message}
onCheckedChange={onChange}
{...fieldProps}
>
<Checkbox.HiddenInput />
<Checkbox.Control />
<Checkbox.Label>Accept Terms of Service</Checkbox.Label>
<Checkbox.ErrorText>{error?.message}</Checkbox.ErrorText>
</Checkbox.Root>
)
}}
/>
<Button
className="mt-1"
emphasis="primary"
size="sm"
type="submit"
variant="fill"
>
Submit
</Button>
</form>
)
}
Tanstack Form
Tanstack Form handles checkbox validation with its built-in validators.
import type {ReactElement} from "react"
import {useForm} from "@tanstack/react-form"
import {Button} from "@qualcomm-ui/react/button"
import {Checkbox} from "@qualcomm-ui/react/checkbox"
interface FormData {
acceptTerms: boolean
newsletter: boolean
}
const defaultFormData: FormData = {
acceptTerms: false,
newsletter: true,
}
const errorMessage = "Please accept the Terms of Service to continue"
export default function CheckboxTanstackFormDemo(): ReactElement {
const form = useForm({
defaultValues: defaultFormData,
onSubmit: async ({value}) => {
// Do something with form data
console.log(value)
},
})
return (
<form
className="flex w-56 flex-col gap-2"
onSubmit={(event) => {
event.preventDefault()
event.stopPropagation()
void form.handleSubmit()
}}
>
<form.Field name="newsletter">
{({handleChange, name, state}) => {
return (
<Checkbox
checked={state.value}
label="Subscribe to our Newsletter"
name={name}
onCheckedChange={handleChange}
/>
)
}}
</form.Field>
<form.Field
name="acceptTerms"
validators={{
onChange: (field) => (field.value ? undefined : errorMessage),
onSubmit: (field) => (field.value ? undefined : errorMessage),
}}
>
{({handleChange, name, state}) => {
const fieldError =
state.meta.errorMap["onChange"] || state.meta.errorMap["onSubmit"]
return (
<Checkbox
checked={state.value}
errorText={fieldError}
invalid={!!fieldError}
label="Accept Terms"
name={name}
onCheckedChange={handleChange}
/>
)
}}
</form.Field>
<Button
className="mt-1"
emphasis="primary"
size="sm"
type="submit"
variant="fill"
>
Submit
</Button>
</form>
)
}
Tanstack form also supports ArkType.
Composite Guidelines
The composite elements are only intended to be used as direct descendants of the <Checkbox.Root> component.
/* Won't work alone ❌ */
<Checkbox.HiddenInput />
<Checkbox.Control />
/* Works as expected ✅ */
<Checkbox.Root>
<Checkbox.HiddenInput />
<Checkbox.Control />
</Checkbox.Root>API
<Checkbox>
The Checkbox extends the Checkbox.Root with the following props:
| Prop | Type |
|---|---|
Props applied to the control element. | |
string | |
Props applied to the error text element. | |
Props applied to the hidden input element. | |
Props applied to the indicator element. | |
Optional label describing the element. Recommended. This element is
automatically associated with the component's input element for
accessibility. | |
Props applied to the label element. |
Composite API
<Checkbox.Root>
| Prop | Type | Default |
|---|---|---|
The controlled checked state of the checkbox | boolean | |
The initial checked state of the checkbox when rendered.
Use when you don't need to control the checked state of the checkbox. | boolean | |
The document's text/writing direction. | 'ltr' | 'rtl' | 'ltr' |
Whether the input is disabled. When true, prevents user interaction and
applies visual styling to indicate the disabled state. | boolean | |
The id of the form that the checkbox belongs to. | string | |
A root node to correctly resolve document in custom environments. i.e.,
Iframes, Electron. | () => | |
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string | |
The ids of the elements that are associated with the checkbox. These will be
automatically generated if omitted. | Partial<{ | |
If true and the checkbox is not checked, the checkbox will be in the
indeterminate state. | boolean | |
Controls the visual error state of the input. When true, applies semantic error
styling to indicate validation failure. | boolean | |
The name of the input field in a checkbox.
Useful for form submission. | string | |
The callback invoked when the checked state changes. | ( | |
The callback invoked when the field is focused. | ( | |
Whether the input is read-only. When true, prevents user interaction while
keeping the input focusable and visible. | boolean | |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement | |
Whether the input is required. When true, the input must have a value for form
validation to pass. | boolean | |
The size of the checkbox and its elements. Governs properties like label font
size, control size, and indicator size. | | 'sm' | 'md' |
The value of checkbox input. Useful for form submission. | string | "on" |
booleanboolean'ltr' | 'rtl'
booleanstring() =>
| Node
| ShadowRoot
| Document
stringPartial<{
control: string
errorText: string
hiddenInput: string
label: string
root: string
}>
booleanindeterminate state.booleanstring(
checked: boolean,
) => void
(
focused: boolean,
) => void
boolean| ReactElement
| ((
props: object,
) => ReactElement)
boolean| 'sm'
| 'md'
| 'lg'
string| Attribute / Property | Value |
|---|---|
className | 'qui-checkbox__root' |
data-active | |
data-disabled | |
data-focus | |
data-focus-visible | |
data-hover | |
data-invalid | |
data-part | 'root' |
data-readonly | |
data-scope | 'checkbox' |
data-state | | 'checked' |
className'qui-checkbox__root'data-activedata-disableddata-focusdata-focus-visibledata-hoverdata-invaliddata-part'root'data-readonlydata-scope'checkbox'data-state| 'checked'
| 'indeterminate'
| 'unchecked'
<Checkbox.Label>
<span> element by default.| Prop | Type |
|---|---|
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
string| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-checkbox__label' |
data-active | |
data-disabled | |
data-focus | |
data-focus-visible | |
data-hover | |
data-invalid | |
data-part | 'label' |
data-readonly | |
data-scope | 'checkbox' |
data-size | | 'sm' |
data-state | | 'checked' |
className'qui-checkbox__label'data-activedata-disableddata-focusdata-focus-visibledata-hoverdata-invaliddata-part'label'data-readonlydata-scope'checkbox'data-size| 'sm'
| 'md'
| 'lg'
data-state| 'checked'
| 'indeterminate'
| 'unchecked'
<Checkbox.Control>
<div> element by
default.| Prop | Type | Default |
|---|---|---|
<CheckboxIndicator /> | ||
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string | |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
string| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-checkbox__control' |
data-active | |
data-disabled | |
data-focus | |
data-focus-visible | |
data-hover | |
data-invalid | |
data-part | 'control' |
data-readonly | |
data-scope | 'checkbox' |
data-size | | 'sm' |
data-state | | 'checked' |
className'qui-checkbox__control'data-activedata-disableddata-focusdata-focus-visibledata-hoverdata-invaliddata-part'control'data-readonlydata-scope'checkbox'data-size| 'sm'
| 'md'
| 'lg'
data-state| 'checked'
| 'indeterminate'
| 'unchecked'
<Checkbox.ErrorText>
<div> element
by default.| Prop | Type | Default |
|---|---|---|
An icon to display next to the error text. | | LucideIcon | <AlertCircle /> |
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string | |
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| LucideIcon
| ReactNode
string| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-input__error-text' |
data-active | |
data-disabled | |
data-focus | |
data-focus-visible | |
data-hover | |
data-invalid | |
data-part | 'error-text' |
data-readonly | |
data-scope | 'checkbox' |
data-state | | 'checked' |
hidden | boolean |
className'qui-input__error-text'data-activedata-disableddata-focusdata-focus-visibledata-hoverdata-invaliddata-part'error-text'data-readonlydata-scope'checkbox'data-state| 'checked'
| 'indeterminate'
| 'unchecked'
hiddenboolean<Checkbox.HiddenInput>
<input> element. Note: do not apply typical input props like disabled
to this element. Those are applied to the root element and propagated via
internal context.| Prop | Type |
|---|---|
id attribute. If
omitted, a unique identifier will be automatically generated for accessibility. | string |
string| Attribute / Property | Value |
|---|---|
className | 'qui-checkbox__hidden-input' |
data-active | |
data-disabled | |
data-focus | |
data-focus-visible | |
data-hover | |
data-invalid | |
data-part | 'hidden-input' |
data-readonly | |
data-scope | 'checkbox' |
data-state | | 'checked' |
style |
className'qui-checkbox__hidden-input'data-activedata-disableddata-focusdata-focus-visibledata-hoverdata-invaliddata-part'hidden-input'data-readonlydata-scope'checkbox'data-state| 'checked'
| 'indeterminate'
| 'unchecked'
style<Checkbox.Indicator>
<div> element by
default.| Prop | Type | Default |
|---|---|---|
<CheckboxIndicatorIcon /> | ||
Allows you to replace the component's HTML element with a different tag or component. Learn more | | ReactElement |
| ReactElement
| ((
props: object,
) => ReactElement)
| Attribute / Property | Value |
|---|---|
className | 'qui-checkbox__indicator' |
data-active | |
data-disabled | |
data-focus | |
data-focus-visible | |
data-hover | |
data-invalid | |
data-part | 'indicator' |
data-readonly | |
data-scope | 'checkbox' |
data-size | | 'sm' |
data-state | | 'checked' |
hidden | boolean |
className'qui-checkbox__indicator'data-activedata-disableddata-focusdata-focus-visibledata-hoverdata-invaliddata-part'indicator'data-readonlydata-scope'checkbox'data-size| 'sm'
| 'md'
| 'lg'
data-state| 'checked'
| 'indeterminate'
| 'unchecked'
hiddenboolean
<label>element by default.