Skip to content
Suluu

SwitchToggle

A compact switch tuned for direct manipulation. Tap anywhere on the track or pull the thumb yourself; it previews the next state under your finger while remaining captured inside a pill that yields and stretches slightly in the same direction, then both layers settle on soft springs.

Preview

Tap or drag the switch

Installation

Registry — recommended

Copies the component into your configured shadcn UI directory and installs Motion.

npx shadcn@latest add https://suluu.site/r/switch-toggle.json

npm package

For centralized upgrades, install the optional ESM package and configure Tailwind source detection as shown below.

pnpm add suluu motion

Usage

Give every switch a stable accessible name. Use defaultChecked for local state, or pair checked with onCheckedChange when your application owns the setting. SwitchToggle renders only the control; visible labels and status text belong to your surrounding markup.

Registry
import { SwitchToggle } from "@/components/ui/switch-toggle"

export function SoundSetting() {
  return (
    <SwitchToggle
      aria-label="Background sounds"
      defaultChecked
      onCheckedChange={(checked) => saveSoundSetting(checked)}
    />
  )
}
npm
// app/globals.css
@import "suluu/styles.css";
@source "../node_modules/suluu/dist";

// component.tsx
import { SwitchToggle } from "suluu/switch-toggle"

export function SoundSetting() {
  return <SwitchToggle aria-label="Background sounds" defaultChecked />
}

Controlled state

Controlled
const [enabled, setEnabled] = useState(false)

<SwitchToggle
  aria-label="Background sounds"
  checked={enabled}
  onCheckedChange={setEnabled}
/>

In context

Pair the spring switch with a persistent setting whose effect is immediate and reversible.

Product updates

A concise weekly note when something meaningful changes.

Props

SwitchToggle accepts safe native button attributes, always uses type="button", and forwards its ref to the button element.

PropTypeDefaultDescription
checkedbooleanControlled checked state.
defaultCheckedbooleanfalseInitial uncontrolled state.
onCheckedChange(checked) => voidRuns when a tap, key press, or drag requests a state change.
disabledbooleanfalseDisables every interaction.
classNamestringClass name applied to the switch.

Theming

Override these variables in your light and dark theme scopes. The registry installs the defaults automatically.

--suluu-switch-backgroundUnchecked track surface.
--suluu-switch-background-checkedChecked track surface.
--suluu-switch-thumbThumb surface.
--suluu-switch-iconUnchecked minus icon.
--suluu-switch-icon-checkedChecked check icon.
--suluu-switch-ringKeyboard focus ring.
--suluu-switch-offsetColor behind the focus ring offset.
--suluu-switch-shadowUnchecked track depth.
--suluu-switch-shadow-checkedChecked track depth and glow.
--suluu-switch-thumb-shadowThumb elevation.

The root exposes data-state and data-dragging for state-specific styling.

Accessibility

The spring switch is a native button with role="switch" and a live aria-checked state. Enter and Space work through native button behavior, focus remains on the control after dragging, and disabled state blocks every input path.

With reduced motion, the control keeps direct dragging but removes spring overshoot, elasticity, pill follow, squash, and path interpolation. The short state change becomes immediate.

↑↓ to navigate↵ to openesc to close