rapidUI

Switch

On/off toggle switch built on Base UI Switch.

Installation

pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/switch.json

Installs to @/components/ui/switch.

Manual installation

Install the dependencies:

pnpm add @base-ui/react@^1.8.0

Copy the source into your project:

components/ui/switch.tsx
'use client'

import { Switch as SwitchPrimitive } from '@base-ui/react/switch'
import { cn } from '@/lib/utils'

function Switch({
	className,
	size = 'default',
	...props
}: SwitchPrimitive.Root.Props & {
	size?: 'sm' | 'default'
}) {
	return (
		<SwitchPrimitive.Root
			data-slot="switch"
			data-size={size}
			className={cn(
				'peer group/switch relative inline-flex shrink-0 cursor-pointer items-center rounded-full border border-transparent transition-all outline-none group-has-[:focus-visible]/field-label:border-transparent group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 p-0.5 data-[size=default]:h-5 data-[size=default]:w-9 data-[size=sm]:h-4 data-[size=sm]:w-7 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-checked:hover:bg-primary/90 data-unchecked:border-input data-unchecked:bg-background data-unchecked:hover:border-primary/90 data-disabled:cursor-not-allowed data-disabled:opacity-50',
				className,
			)}
			{...props}
		>
			<SwitchPrimitive.Thumb
				data-slot="switch-thumb"
				className="pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-3.5 group-data-[size=sm]/switch:size-2.5 group-data-[size=default]/switch:data-checked:translate-x-4 group-data-[size=sm]/switch:data-checked:translate-x-3 data-checked:bg-background group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0 data-unchecked:bg-foreground group-hover/switch:data-unchecked:bg-primary/90"
			/>
		</SwitchPrimitive.Root>
	)
}

export { Switch }

A switch component that allows users to toggle between two states (on/off). Built on top of Base UI Switch, it follows WAI-ARIA design patterns and is fully accessible.

Features

  • Two sizes: default and sm
  • Controlled (checked / onCheckedChange) and uncontrolled (defaultChecked) modes
  • Disabled state
  • Invalid state via aria-invalid
  • Enlarged hit area for easier clicking
  • Works with Label or the Field components, including selectable choice cards
  • Keyboard navigation and screen reader support

Usage

import { Switch } from '@/components/ui/switch'
import { Label } from '@/components/ui/label'

export function MyForm() {
  return (
    <div className="flex items-center gap-2">
      <Switch id="airplane-mode" />
      <Label htmlFor="airplane-mode">Airplane mode</Label>
    </div>
  )
}

Size

<Switch size="sm" />
<Switch size="default" />

With Field

import { Field, FieldContent, FieldDescription, FieldLabel } from '@/components/ui/field'
import { Switch } from '@/components/ui/switch'

<Field orientation="horizontal">
  <FieldContent>
    <FieldLabel htmlFor="share">Share across devices</FieldLabel>
    <FieldDescription>Focus is shared across devices.</FieldDescription>
  </FieldContent>
  <Switch id="share" />
</Field>

Examples

Default

Sizes

sm suits dense tables and toolbars; default suits forms and settings pages.

Horizontal

Several small switches in a row as quick filters above a case list.

Disabled State

Settings the resident can't change. Set data-disabled="true" on the Field to dim the label and description too.

Invalid

Set aria-invalid on the switch and data-invalid on the Field, and explain the problem with FieldError. Turn the switch on to clear the error.

With Description

A horizontal Field with the label and description on the left and the switch on the right.

Choice Card

Wrap a horizontal Field in a FieldLabel to make the whole card toggle the switch – here for home care services.

Settings

A notification settings card grouping switches with FieldGroup and FieldSeparator.

Accessibility

The Switch component follows WAI-ARIA guidelines for switches:

  • Uses proper ARIA roles (switch)
  • Supports keyboard navigation:
    • Tab: Move focus to the switch
    • Space: Toggle the switch state
  • Provides proper labeling and descriptions
  • Maintains focus management
  • Includes visual focus indicators
  • Supports screen reader announcements

Best Practices

  • Always provide labels for switches
  • Use clear, action-oriented labels
  • Consider adding descriptions for complex toggles
  • Use appropriate spacing between switch and label
  • Provide clear visual feedback for state changes
  • Consider using icons for additional visual clarity
  • Use switches for binary choices (on/off, yes/no)
  • Checkbox
  • Radio Group
  • Toggle
  • Field