Open UI

Toggle (Switch)

A toggle is used to switch between two possible states, commonly enabled or disabled states.

import { Toggle } from "@opengovsg/oui"export const Example = () => {  return <Toggle>Toggle</Toggle>}

Usage

import { Toggle } from "@opengovsg/oui"
<Toggle>Enable notifications</Toggle>

Alternatively, install the component as local source via the shadcn CLI:

npx shadcn@latest add https://oui.open.gov.sg/r/toggle.json
pnpm dlx shadcn@latest add https://oui.open.gov.sg/r/toggle.json
npx shadcn@latest add https://oui.open.gov.sg/r/toggle.json
bunx --bun shadcn@latest add https://oui.open.gov.sg/r/toggle.json

The Toggle component allows users to switch between two states (on/off). It is built on React Aria's Switch.

If the component does not have a visible label (by passing children), an aria-label prop must be passed instead to identify it to assistive technology.

Examples

With Label

Pass children to add a visible text label next to the toggle.

import { Toggle } from "@opengovsg/oui"export const Example = () => {  return <Toggle>Enable notifications</Toggle>}

Label Placement

Use the labelPlacement prop to position the label before or after the toggle. Defaults to "end".

import { Toggle } from "@opengovsg/oui"export const Example = () => {  return (    <div className="flex flex-col gap-4">      <Toggle labelPlacement="end">Label at end (default)</Toggle>      <Toggle labelPlacement="start">Label at start</Toggle>    </div>  )}

Sizes

Use the size prop to change the size of the toggle. Defaults to "md".

import { Toggle } from "@opengovsg/oui"export const Example = () => {  return (    <div className="flex flex-col gap-4">      <Toggle size="xs">Extra small</Toggle>      <Toggle size="sm">Small</Toggle>      <Toggle size="md">Medium (default)</Toggle>    </div>  )}

Thumb Icon

Use the thumbIcon prop to display an icon inside the toggle thumb. The prop accepts a React element or a render function that receives SwitchRenderProps (including isSelected and className).

import { Check, X } from "lucide-react"import { Toggle } from "@opengovsg/oui"export const Example = () => {  return (    <Toggle      aria-label="Toggle"      thumbIcon={({ isSelected, className }) =>        isSelected ? (          <Check className={className} />        ) : (          <X className={className} />        )      }    />  )}

Disabled

Use the isDisabled prop to disable the toggle.

import { Toggle } from "@opengovsg/oui"export const Example = () => {  return (    <div className="flex flex-col gap-4">      <Toggle isDisabled>Disabled (off)</Toggle>      <Toggle isDisabled defaultSelected>        Disabled (on)      </Toggle>    </div>  )}

Controlled

Use the isSelected and onChange props to control the toggle state programmatically.

import { useState } from "react"import { Toggle } from "@opengovsg/oui"export const Example = () => {  const [isSelected, setIsSelected] = useState(false)  return (    <div className="flex flex-col gap-2">      <Toggle isSelected={isSelected} onChange={setIsSelected}>        Dark mode      </Toggle>      <p className="text-base-content-medium text-sm">        Dark mode is {isSelected ? "on" : "off"}.      </p>    </div>  )}

Events

Toggle supports the following event handlers, inherited from React Aria's Switch:

  • onChange — Called when the selection state changes, receiving a boolean.
  • onFocus / onBlur — Called when the toggle gains or loses focus.
  • onFocusChange — Called when the focus state changes, receiving a boolean.
  • onKeyDown / onKeyUp — Called on keyboard events.
  • onHoverStart / onHoverEnd / onHoverChange — Called on hover events.

Accessibility

  • Built on the WAI-ARIA switch role, providing correct semantics for assistive technology.
  • Keyboard interaction: Press Space to toggle the switch state.
  • Label is automatically associated with the switch input.
  • Disabled and selected states are exposed to assistive technology.
  • If no visible label is provided via children, an aria-label prop must be set.

Slots

  • base: The root container wrapper with label.
  • track: The toggle track (background).
  • thumb: The toggle thumb (sliding circle).
  • thumbIcon: The icon inside the thumb.

Custom Styles

You can customize the Toggle component by passing custom Tailwind CSS classes to the component slots via the classNames prop.

import { Toggle } from "@opengovsg/oui"export const Example = () => {  return (    <Toggle      defaultSelected      classNames={{        base: "gap-4 rounded-lg bg-blue-50 px-4 py-3",        track: "rounded-sm bg-blue-200 in-selected:bg-blue-600",        thumb: "rounded-sm border-0 shadow-md",      }}    >      Squared toggle    </Toggle>  )}

Props

Toggle

PropTypeDefaultDescription
childrenReact.ReactNode-The label content. Required if aria-label is not set.
aria-labelstring-Accessible label. Required if children is not set.
isSelectedboolean-The current selection state (controlled)
defaultSelectedboolean-The default selection state (uncontrolled)
onChange(isSelected: boolean) => void-Callback fired when the selection state changes
thumbIconReact.ReactElement | ((props: ToggleThumbIconProps) => React.ReactNode)-Icon to display inside the thumb. Render function receives isSelected and className.
labelPlacement"start" | "end""end"Where to place the label relative to the toggle
size"xs" | "sm" | "md""md"The size of the toggle
colorScheme"success""success"The color scheme of the toggle
isDisabledbooleanfalseWhether the toggle is disabled
isReadOnlybooleanfalseWhether the toggle is read-only
namestring-The name of the input, used when submitting a form
valuestring-The value of the input, used when submitting a form
autoFocusbooleanfalseWhether the toggle should receive focus on render
onFocus(e: FocusEvent) => void-Called when the toggle receives focus
onBlur(e: FocusEvent) => void-Called when the toggle loses focus
onFocusChange(isFocused: boolean) => void-Called when the focus state changes
onKeyDown(e: KeyboardEvent) => void-Called when a key is pressed
onKeyUp(e: KeyboardEvent) => void-Called when a key is released
classNamesSlotsToClasses<ToggleSlots>-Custom CSS classes for component slots

On this page