RoadieRoadie
  • Home
  • Foundations
  • Tokens
  • Components
  • Charts
  • Widgets
  • Appearance
HomeFoundationsComponents
Appearance

Components

  • Navigation

    • Breadcrumb
    • Navigator
    • Steps
    • Tabs
  • Layout

    • Pane
    • ScrollArea
    • Separator
  • Actions

    • Button
    • IconButton
    • Toggle
    • Toggle group
  • Forms

    • Forms overview
    • Autocomplete
    • Checkbox
    • Combobox
    • Field
    • Fieldset
    • Input
    • Label
    • Number field
    • OTP field
    • Radio group
    • Select
    • Slider
    • Switch
    • Textarea
  • Overlays

    • Dialog
    • Drawer
    • Menu
    • Popover
    • Toast
    • Tooltip
  • Collections

    • Accordion
    • Card
    • Carousel
    • Collapsible
    • DataTable
    • List
    • Marquee
    • Table
  • Status

    • Badge
    • Callout
    • Countdown
    • Empty state
    • Meter
    • Progress
    • Skeleton
    • Sparkline
    • StatTile
  • Media & brand

    • Avatar
    • Icon Tile
    • Image
    • Logo
    • QR code
    • SpotIllustration
  • Text

    • CalendarTile
    • Code
    • DateTime
    • Duration
    • Highlight
    • Mark
    • Prose

Switch

An on or off control for a setting that applies straight away.

Import

import { Switch } from '@oztix/roadie-components/switch'

Examples

Default

<Switch label='Email me when tickets go on sale' />

The row fills its container, with the label on the left and the switch on the right. Add className='justify-start' to keep them together.

Settings list

Add description for a second line. It is announced as the switch's description, not as part of its name.

<div className='grid max-w-md divide-y divide-subtler'>
  <Switch
    className='py-3'
    label='Email me when tickets go on sale'
    description='One email per event, sent when the general sale opens.'
    defaultChecked
  />
  <Switch
    className='py-3'
    label='Presale alerts'
    description='Early access codes for artists you follow.'
  />
  <Switch
    className='py-3'
    label='Event reminders'
    description='A reminder the day before doors open at The Tin Lantern.'
    defaultChecked
  />
</div>

Sizes

<div className='grid max-w-xs gap-3'>
  <Switch size='sm' label='Small' defaultChecked />
  <Switch size='md' label='Medium' defaultChecked />
</div>

States

<div className='grid max-w-xs gap-4'>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Off</p>
    <Switch aria-label='Off' />
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>On</p>
    <Switch aria-label='On' defaultChecked />
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Disabled</p>
    <Switch label='Presale alerts' disabled />
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Disabled and on</p>
    <Switch label='Presale alerts' disabled defaultChecked />
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Invalid</p>
    <Switch label='Instant payouts' invalid />
  </div>
  <div className='grid gap-1'>
    <p className='text-sm text-subtle'>Invalid and on</p>
    <Switch label='Instant payouts' invalid defaultChecked />
  </div>
</div>

With Field

Inside Field, Switch takes invalid, required and disabled from the field, and is described by Field.HelperText or Field.ErrorText.

function Example() {
  const [instant, setInstant] = useState(true)
  return (
    <Field invalid={instant} className='max-w-md'>
      <Switch
        label='Instant payouts'
        checked={instant}
        onCheckedChange={setInstant}
      />
      <Field.ErrorText>
        Verify your bank account to turn on instant payouts.
      </Field.ErrorText>
    </Field>
  )
}

render(<Example />)

Field.Label names a bare switch, and clicking the label toggles it.

<Field className='max-w-md'>
  <Field.Label>Resale listings</Field.Label>
  <Switch />
  <Field.HelperText>Let fans buy tickets you can no longer use.</Field.HelperText>
</Field>

Composition

Switch renders its own thumb. Pass Switch.Thumb as a child to style it.

<Switch aria-label='Dark mode'>
  <Switch.Thumb className='shadow-md' />
</Switch>

Guidelines

  • Use a switch when the change applies at once, like a notification setting. For a yes or no choice that waits for a submit button, like accepting terms, use a checkbox.
  • Name the setting, not the action. "Presale alerts", not "Turn on presale alerts". The switch already says on or off.

Accessibility

  • Keyboard: Tab moves focus to the switch. Space or Enter toggles it.
  • ARIA: Base UI renders role="switch" with aria-checked, plus a hidden checkbox so the value submits with a form.
  • Naming: every switch needs a name. Use label, Field.Label, or aria-label on a bare switch.
  • Not colour alone: a tick shows in the track when the switch is on. It is decorative and hidden from assistive tech, since aria-checked carries the state.
  • Motion: the thumb's slide and the tick's fade stop when the user prefers reduced motion.

API reference

Switch

idstring

The id of the hidden input element. When `nativeButton` is `true`, the id is applied to the root element.

checkedboolean

Whether the switch is currently active. To render an uncontrolled switch, use the `defaultChecked` prop instead.

defaultCheckedboolean

Whether the switch is initially active. To render a controlled switch, use the `checked` prop instead.

Defaults to false.

disabledboolean

Whether the component should ignore user interaction.

Defaults to false.

inputRefRef<HTMLInputElement>

A ref to access the hidden `<input>` element.

namestring

Identifies the field when a form is submitted.

formstring

Identifies the form that owns the hidden input. Useful when the switch is rendered outside the form.

onCheckedChange((checked: boolean, eventDetails: { reason: "none"; event: Event; cancel: () => void; allowPropagation: () => void; isCanceled: boolean; isPropagationAllowed: boolean; trigger: Element; }) => void)

Event handler called when the switch is activated or deactivated.

readOnlyboolean

Whether the user should be unable to activate or deactivate the switch.

Defaults to false.

requiredboolean

Whether the user must activate the switch before submitting a form.

Defaults to false.

valuestring

The value submitted with the form when the switch is on. By default, switch submits the "on" value, matching native checkbox behavior.

uncheckedValuestring

The value submitted with the form when the switch is off. By default, unchecked switches do not submit any value, matching native checkbox behavior.

classNamestring | ((state: SwitchRootState) => string)

CSS class applied to the element, or a function that returns a class based on the component's state.

size"sm" | "md"

Defaults to 'md'.

labelReactNode

Renders a label beside the switch. With `label` or `description`, `className` goes on the row.

descriptionReactNode

Secondary text under the label, announced as the description.

invalidboolean

Marks the switch invalid. Inherits from `Field` when unset.

Inherited from NonNativeButtonProps

nativeButtonboolean

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.

Defaults to false.

Switch.Thumb

No additional props. It forwards all standard HTML attributes to the underlying element.

Previous page← SliderNext pageTextarea →