Checkbox
A clickable checkbox control with configurable icons, intents, spacing, and scale.

The Checkbox component allows users to toggle a boolean value.
It can be used uncontrolled, managing its own state from an optional defaultChecked starting value, or controlled, showing whatever you pass as checked. It can also show its own clickable text label.
When used inside a Fieldset, clicking the fieldset label also toggles the checkbox.
Import
import { Checkbox } from "@rbxts/react-clean-ui";Basic usage
The checkbox starts unchecked by default.
Behaviour change in 2.0.0
Passing checked now makes the checkbox controlled: it always shows the prop's value, and a click only calls onChange(!checked). A checked without an onChange that feeds the new value back leaves the checkbox frozen. onChange also no longer fires on mount or when the checked prop changes, only when the user toggles it. Use defaultChecked for the old "initial value only" behaviour, and read the initial value yourself if you relied on the mount-time onChange call.
Uncontrolled
Leave checked unset and the checkbox keeps its own state. Use defaultChecked to choose the starting value.
<Checkbox defaultChecked /><Checkbox
defaultChecked={true}
onChange={(checked) => {
print(`Checked: ${checked}`);
}}
/>defaultChecked is only read when the checkbox mounts. Changing it later has no effect.
Controlled
Pass checked to drive the checkbox from your own state. Clicking it calls onChange with the requested value but changes nothing by itself, so feed the value back through checked.
import React, { useState } from "@rbxts/react";
import { Checkbox } from "@rbxts/react-clean-ui";
export function ControlledCheckbox() {
const [checked, setChecked] = useState(false);
return (
<Checkbox
checked={checked}
onChange={setChecked}
/>
);
}Because the visual always follows checked, you can also reject or change the value in onChange, or update checked from elsewhere. Changing checked from outside does not call onChange.
With a label
Set label to show text next to the box. Clicking the text toggles the checkbox, the same as clicking the box.
The label text uses the theme typography for the checkbox's scale, and the gap between box and label is half the checkbox's resolved spacing at that scale, rounded up. Both can be changed through theme.components.checkbox.label (see Theme values). For richer label content, such as rich text or other components, use a Fieldset instead.
With a fieldset
Use Fieldset.Control and Fieldset.Label to associate the checkbox with a label.
<Fieldset checkbox>
<Fieldset.Control>
<Checkbox
onChange={(checked) => {
print(`Checked: ${checked}`);
}}
/>
</Fieldset.Control>
<Fieldset.Label>
<Text text="Receive email notifications" />
</Fieldset.Label>
</Fieldset>When the user clicks either the checkbox or its label, the checked state will toggle.
Scale and spacing
The scale prop controls the size of the checkbox icon.
The spacing prop controls the internal padding around the icon.
<Fieldset checkbox>
<Fieldset.Control>
<Checkbox
scale="xl"
spacing="xl"
/>
</Fieldset.Control>
<Fieldset.Label>
<Text text="<b>xl</b> Scale and Spacing" />
</Fieldset.Label>
</Fieldset>Scale and spacing can be configured independently.
<Fieldset checkbox>
<Fieldset.Control>
<Checkbox
scale="xs"
spacing="xl"
/>
</Fieldset.Control>
<Fieldset.Label>
<Text text="<b>xs</b> Scale with <b>xl</b> Spacing" />
</Fieldset.Label>
</Fieldset>Custom icons
Use icon-checked and icon-unchecked to customise the icon displayed for each state.
<Checkbox
icon-checked="thumbs-up"
icon-unchecked="thumbs-down"
/>If icon-unchecked is omitted, no icon is displayed while the checkbox is unchecked.
Checked and unchecked intents
The appearance of each state can be configured independently.
<Checkbox
icon-checked="thumbs-up"
icon-unchecked="thumbs-down"
intent-checked="info"
intent-unchecked="danger"
/>The selected intent controls the border and icon colours for each state.
Complete example
<Fieldset checkbox>
<Fieldset.Control>
<Checkbox
defaultChecked
icon-checked="thumbs-up"
icon-unchecked="thumbs-down"
intent-checked="info"
intent-unchecked="danger"
onChange={(checked) => {
print(`Checked: ${checked}`);
}}
/>
</Fieldset.Control>
<Fieldset.Label>
<Text text="Enable advanced mode" />
</Fieldset.Label>
</Fieldset>Props
Checkbox-specific props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | undefined | Controlled checked state. When set, the checkbox always shows this value. |
defaultChecked | boolean | false | Starting state when uncontrolled (checked unset). Only read on mount. |
onChange | (value: boolean) => void | undefined | Called with the new value when the user toggles the checkbox. Never called on mount or when checked changes. |
label | string | undefined | Text shown next to the box. Clicking it toggles the checkbox. |
name | string | "Checkbox" | Name of the root instance. |
icon-checked | IconName | "check" | Icon displayed while checked. |
icon-unchecked | IconName | undefined | Icon displayed while unchecked. |
intent-checked | Intent | "success" | Intent used for the checked border and icon colours. |
intent-unchecked | Intent | "primary" | Intent used for the unchecked border and icon colours. |
Shared props
The checkbox also supports props inherited from the following interfaces.
| Interface | Purpose |
|---|---|
IntentElementProps | Configures the checkbox's base background intent, independent of intent-checked/intent-unchecked. |
PaddingProps | Configures individual padding values. |
BackgroundElementProps | Configures background colour and transparency. |
SpacedElementProps | Configures theme-based internal spacing. |
ScalableElementProps | Configures the icon scale. |
Behaviour
- The checkbox is unchecked by default.
- With
checkedset, the checkbox is controlled: it showschecked, and a click callsonChange(!checked)without changing anything internally. Withoutchecked, it starts atdefaultCheckedand flips its own state on each click before callingonChange. - Clicking the box, its
label, or a pairedFieldset.Labeltoggles the checkbox. onChangeonly fires in response to a user toggle. It never fires on mount, and never fires when a controlledcheckedprop changes.- Without
label, the checkbox renders a singleImageButtonnamed byname. Withlabel, the root becomes a transparent, content-sizedFramenamed byname, holding the box (renamed"CheckboxBox") and a"CheckboxLabel"button with the text. The label button is not gamepad-selectable, so gamepad selection stays on the box. - Setting or clearing
labelafter mount remounts the box.
The state transitions follow this pattern:
false → true → falseTheme values
The checkbox uses values from theme.components.checkbox for:
- Corner radius
- Border thickness and transparency
- Border and icon colours, based on the checked/unchecked intent
- Default spacing/padding
- Background image
- The optional
labelstyling:label.typography— merged over the theme typography for the checkbox'sscalelabel.textColor— the label text colour; unset usesText's default text colourlabel.gap— the gap between box and label, in pixels; unset uses half the resolved spacing at the checkbox'sscale, rounded up
No shipped theme sets checkbox.label.
const theme = createTheme({
components: {
checkbox: {
label: {
textColor: Color3.fromHex("#9CA3AF"),
gap: 12,
},
},
},
});The solid background colour (based on the intent prop's default state) and background transparency fall back to the values from theme.components.button.