Switch
A control that allows the user to toggle between checked and not checked. It functions as an alternative to the Checkbox component.
import * as React from 'react'; import { Switch } from 'gnome-ui/switch'; import { Field } from 'gnome-ui/field'; export function SwitchDefault() { return ( <Field.Root className="flex items-center gap-3 w-full max-w-xs"> <Switch.Root id="airplane-mode" className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring bg-input data-[checked]:bg-primary disabled:cursor-not-allowed disabled:opacity-50"> <Switch.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-200 translate-x-0 data-[checked]:translate-x-4" /> </Switch.Root> <Field.Label htmlFor="airplane-mode" className="text-sm font-medium text-foreground cursor-pointer select-none"> Airplane mode </Field.Label> </Field.Root> ); }
Anatomy
import { Switch } from 'gnome-ui/switch'; <Switch.Root> <Switch.Thumb /> </Switch.Root>
Examples
Disabled State
The Switch can be disabled. The state is communicated via the disabled prop and visually via Tailwind classes.
import * as React from 'react'; import { Switch } from 'gnome-ui/switch'; import { Field } from 'gnome-ui/field'; export function SwitchDisabled() { return ( <div className="flex flex-col gap-4 w-full max-w-xs"> <Field.Root className="flex items-center gap-3"> <Switch.Root disabled className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring bg-input data-[checked]:bg-primary disabled:cursor-not-allowed disabled:opacity-50"> <Switch.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-200 translate-x-0 data-[checked]:translate-x-4" /> </Switch.Root> <Field.Label className="text-sm font-medium text-muted-foreground select-none cursor-not-allowed"> Disabled (Off) </Field.Label> </Field.Root> <Field.Root className="flex items-center gap-3"> <Switch.Root disabled defaultChecked className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring bg-input data-[checked]:bg-primary disabled:cursor-not-allowed disabled:opacity-50"> <Switch.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-200 translate-x-0 data-[checked]:translate-x-4" /> </Switch.Root> <Field.Label className="text-sm font-medium text-muted-foreground select-none cursor-not-allowed"> Disabled (On) </Field.Label> </Field.Root> </div> ); }
Settings List Layout
Switches are often used in settings panels. They pair nicely with icons to build intuitive preference menus.
Connectivity
Manage your networks and notifications.
import * as React from 'react'; import { Switch } from 'gnome-ui/switch'; import { Field } from 'gnome-ui/field'; import { Shield, Bell, Wifi } from 'lucide-react'; export function SwitchWithIcons() { return ( <div className="flex flex-col gap-4 w-full max-w-sm rounded-xl border border-border bg-card p-5 shadow-sm"> <div className="flex flex-col gap-1 mb-2"> <h3 className="text-base font-semibold text-foreground">Connectivity</h3> <p className="text-sm text-muted-foreground">Manage your networks and notifications.</p> </div> <Field.Root className="flex items-center justify-between"> <Field.Label className="flex items-center gap-2 text-sm font-medium text-foreground cursor-pointer select-none"> <Icons.Wifi className="size-4 text-muted-foreground" /> Wireless Network </Field.Label> <Switch.Root defaultChecked className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring bg-input data-[checked]:bg-primary disabled:cursor-not-allowed disabled:opacity-50"> <Switch.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-200 translate-x-0 data-[checked]:translate-x-4" /> </Switch.Root> </Field.Root> <Field.Root className="flex items-center justify-between"> <Field.Label className="flex items-center gap-2 text-sm font-medium text-foreground cursor-pointer select-none"> <Icons.Bell className="size-4 text-muted-foreground" /> Push Notifications </Field.Label> <Switch.Root defaultChecked className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring bg-input data-[checked]:bg-primary disabled:cursor-not-allowed disabled:opacity-50"> <Switch.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-200 translate-x-0 data-[checked]:translate-x-4" /> </Switch.Root> </Field.Root> <Field.Root className="flex items-center justify-between mt-2 pt-4 border-t border-border"> <Field.Label className="flex items-center gap-2 text-sm font-medium text-foreground cursor-pointer select-none"> <Icons.Shield className="size-4 text-[oklch(0.55_0.12_250)]" /> Firewall </Field.Label> {/* We use a custom color for this critical option */} <Switch.Root defaultChecked className="relative inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring bg-input data-[checked]:bg-primary disabled:cursor-not-allowed disabled:opacity-50 data-[checked]:bg-[oklch(0.55_0.12_250)]"> <Switch.Thumb className="pointer-events-none block size-4 rounded-full bg-background shadow-lg ring-0 transition-transform duration-200 translate-x-0 data-[checked]:translate-x-4" /> </Switch.Root> </Field.Root> </div> ); }
SwitchRoot
Represents the switch itself.
Renders a <span> element and a hidden <input> beside.
Documentation: Base UI Switch
API reference
Root
Represents the switch itself.
Renders a <span> element and a hidden <input> beside.
Root Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| name | string | - | Identifies the field when a form is submitted. |
| defaultChecked | boolean | false | Whether the switch is initially active.To render a controlled switch, use the checked prop instead. |
| checked | boolean | - | Whether the switch is currently active.To render an uncontrolled switch, use the defaultChecked prop instead. |
| onCheckedChange | ((checked: boolean, eventDetails: Switch.Root.ChangeEventDetails) => void) | - | Event handler called when the switch is activated or deactivated. |
| value | string | - | The value submitted with the form when the switch is on. By default, switch submits the "on" value, matching native checkbox behavior. |
| nativeButton | boolean | false | Whether the component renders a native <button> element when replacing it
via the render prop.
Set to true if the rendered element is a native button. |
| uncheckedValue | string | - | The value submitted with the form when the switch is off. By default, unchecked switches do not submit any value, matching native checkbox behavior. |
| disabled | boolean | false | Whether the component should ignore user interaction. |
| readOnly | boolean | false | Whether the user should be unable to activate or deactivate the switch. |
| required | boolean | false | Whether the user must activate the switch before submitting a form. |
| inputRef | Ref<HTMLInputElement> | - | A ref to access the hidden <input> element. |
| id | string | - | The id of the switch element. |
| className | string | ((state: Switch.Root.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: Switch.Root.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: Switch.Root.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Root Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| data-checked | - | Present when the switch is checked. |
| data-unchecked | - | Present when the switch is not checked. |
| data-disabled | - | Present when the switch is disabled. |
| data-readonly | - | Present when the switch is readonly. |
| data-required | - | Present when the switch is required. |
| data-valid | - | Present when the switch is in valid state (when wrapped in Field.Root). |
| data-invalid | - | Present when the switch is in invalid state (when wrapped in Field.Root). |
| data-dirty | - | Present when the switch's value has changed (when wrapped in Field.Root). |
| data-touched | - | Present when the switch has been touched (when wrapped in Field.Root). |
| data-filled | - | Present when the switch is active (when wrapped in Field.Root). |
| data-focused | - | Present when the switch is focused (when wrapped in Field.Root). |
Thumb
The movable part of the switch that indicates whether the switch is on or off.
Renders a <span>.
Thumb Props:
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | ((state: Switch.Thumb.State) => string | undefined) | - | CSS class applied to the element, or a function that returns a class based on the component’s state. |
| style | CSSProperties | ((state: Switch.Thumb.State) => CSSProperties | undefined) | - | - |
| render | ReactElement | ((props: HTMLProps, state: Switch.Thumb.State) => ReactElement) | - | Allows you to replace the component’s HTML element
with a different tag, or compose it with another component.Accepts a ReactElement or a function that returns the element to render. |
Thumb Data Attributes:
| Attribute | Type | Description |
|---|---|---|
| data-checked | - | Present when the switch is checked. |
| data-unchecked | - | Present when the switch is not checked. |
| data-disabled | - | Present when the switch is disabled. |
| data-readonly | - | Present when the switch is readonly. |
| data-required | - | Present when the switch is required. |
| data-valid | - | Present when the switch is in valid state (when wrapped in Field.Root). |
| data-invalid | - | Present when the switch is in invalid state (when wrapped in Field.Root). |
| data-dirty | - | Present when the switch's value has changed (when wrapped in Field.Root). |
| data-touched | - | Present when the switch has been touched (when wrapped in Field.Root). |
| data-filled | - | Present when the switch is active (when wrapped in Field.Root). |
| data-focused | - | Present when the switch is focused (when wrapped in Field.Root). |
Slider
An input where the user selects a value from within a given range.
Tabs
A component for toggling between related panels. `Tabs.Indicator` is placed **inside** `Tabs.List` and uses CSS variables (`--active-tab-left`, `--active-tab-width`, etc.) to automatically position itself over the active tab.