Switch
An on/off toggle with an animated sliding thumb and intent-driven colors.
Switch is a themed on/off toggle built on Roblox's native ImageButton: a pill-shaped track with a circular thumb that slides between an off (left) and on (right) position.
Import
import { Switch } from "@rbxts/react-clean-ui";Basic usage
The switch starts off by default.
Behaviour change in 2.0.0
Passing checked now makes the switch 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 switch 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 switch keeps its own state. Use defaultChecked to choose the starting value.
<Switch defaultChecked /><Switch
defaultChecked={true}
onChange={(checked) => {
print(`Checked: ${checked}`);
}}
/>defaultChecked is only read when the switch mounts. Changing it later has no effect.
Controlled
Pass checked to drive the switch from your own state, the same contract as Checkbox. 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 { Switch } from "@rbxts/react-clean-ui";
export function ControlledSwitch() {
const [enabled, setEnabled] = useState(false);
return (
<Switch
checked={enabled}
onChange={setEnabled}
/>
);
}The thumb animates whenever the checked prop changes, including when you change it from elsewhere. Changing checked from outside does not call onChange.
With a fieldset
Use Fieldset.Control and Fieldset.Label to associate the switch with a label.
<Fieldset checkbox>
<Fieldset.Control>
<Switch
onChange={(checked) => {
print(`Checked: ${checked}`);
}}
/>
</Fieldset.Control>
<Fieldset.Label>
<Text text="Enable notifications" />
</Fieldset.Label>
</Fieldset>When the user clicks either the switch or its label, the checked state toggles.
Intents
Set intent to control the track's on-state (checked) background and border colors.
<Switch defaultChecked intent="success" />
<Switch defaultChecked intent="danger" />The off-state track color is always the theme's static color, regardless of intent. There is no hover state.
Disabled state
Set disabled to prevent interaction. The track and thumb render at a flat, dimmed transparency, and both clicking the switch and activating a paired Fieldset.Label are ignored.
<Switch defaultChecked disabled />
<Switch disabled />A disabled switch never calls onChange. A controlled switch can still be changed through checked while disabled.
Ordering in a layout
Use LayoutOrder to position the switch inside a list layout such as VStack or HStack. When unset, Roblox's default (0) is used.
<VStack>
<Switch LayoutOrder={1} defaultChecked />
<Switch LayoutOrder={2} />
<Switch LayoutOrder={3} intent="danger" />
</VStack>Props
Switch-specific props
| Prop | Type | Default | Description |
|---|---|---|---|
checked | boolean | undefined | Controlled checked state. When set, the switch 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 switch. Never called on mount or when checked changes. |
disabled | boolean | false | Disables interaction and renders a dimmed appearance. |
name | string | "Switch" | Sets the rendered instance's Name. |
LayoutOrder | number | undefined | Native Roblox layout order. Unset leaves Roblox's default 0. |
Shared props
The switch also supports props inherited from the following interfaces.
| Interface | Purpose |
|---|---|
IntentElementProps | Configures the intent used to resolve the on-state track/border colors. |
BackgroundElementProps | Configures BackgroundTransparency. BackgroundColor3 has no effect — the track color is always driven by the theme and animated by intent/checked state. BackgroundTransparency is ignored while disabled. |
ZIndexElementProps | Configures the switch's ZIndex. |
Behaviour
- The switch is off by default.
- With
checkedset, the switch 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 switch, or a paired
Fieldset.Label, toggles it, unlessdisabled. onChangeonly fires in response to a user toggle. It never fires on mount, never fires when a controlledcheckedprop changes, and never fires whiledisabled.- The thumb's horizontal position and the track's background/border colors animate together, driven by a single tween progress value, over
theme.components.switch.animation.durationseconds. A duration of0snaps instantly instead of animating. - The on-state track/border colors are resolved from
intent(layered overtheme.colors.intents); the off-state colors are always the theme's static, non-intent colors. - When
disabled, both the track and thumb render at a flat dimmed transparency, overriding rather than blending with their normal transparency. - The thumb's diameter is derived from the track height and its inset, not independently configurable.
The state transitions follow this pattern:
false → true → falseTheme values
The switch uses values from theme.components.switch for:
- The track's fixed width and height (the switch does not auto-size or accept size override props)
- Corner radius and border thickness of the track
- The transparency applied to both track and thumb while
disabled - The tween duration used to animate the thumb position and track colors
- The off-state track background color, background transparency, and border color
- Optional per-intent color overrides for the on-state track/border colors, layered on top of
theme.colors.intents - The thumb's inset from the track edge (which also determines its diameter), corner radius, background color, background transparency, border color, border thickness, and box shadow
These values can be changed by providing a custom Clean UI theme.