Sakuga Back to Sakuga
Theme
Sound
Jump to a component

Core · Actions

Switch

Switch turns one thing on or off, with its name as the label (the visible text sits beside it). on is the state; disabled greys it.

@anicanon/sakuga/uiv1.0Used onWeb · iOS · Android

Live, from @anicanon/sakuga 2.0.0

Sakuga for iOS and Android is coming

iOS

Coming soon

Switch for iOS is in the roughs. The tokens it will read are the ones on this page, the same on every platform.

Android

Coming soon

Switch for Android is in the roughs. The tokens it will read are the ones on this page, the same on every platform.

Use it for
One setting that takes effect the moment it changes: Loop this track, Name who speaks.
Not for

Guidelines

  • Use it for a setting that takes effect at once (Lower the music under voices, Name who speaks, Loop this track).
  • A choice between named options is a SegmentedControl, not a switch.
  • The thumb crosses the track on motion-fast and stretches while held.
  • With sound on, turning it on or off plays the on or off sound, by press, key or slide (README · Sound).
  • showLabel sets the label beside it, the whole row toggling: the settings row of a panel (Loops without a seam).
  • hint is a quiet line under the label saying what the setting does; a child sits at the row's end, before the switch (the audio's language).
  • With onChange, the knob can be slid along its track; let go past the middle and the switch is on. A press still flips it.
SwitchExample.jsxReact
import { useState } from 'react';
import { Switch } from '@anicanon/sakuga/ui';

export default function SwitchExample() {
  const [on, setOn] = useState(true);
  const [on2, setOn2] = useState(false);
  return (
    <>
      <Switch on={on} onChange={setOn} label="Name who speaks" />
      <Switch on={on2} onChange={setOn2} label="Loop this track" />
      <Switch on disabled label="Locked" />
    </>
  );
}

PropsSwitchProps

labelrequired
string
The setting's name, read by screen readers.
on
boolean
showLabel
boolean
Sets the label beside it; the whole row toggles.
hint
string
With showLabel: a quiet line under the label.
disabled
boolean
onChange
(on: boolean) => void
children
ReactNode
With showLabel: sits at the row's end, before the switch.
className
string
SwitchExample.swiftiOS · coming soon
SwitchExample.ktAndroid · coming soon

Each token reads a role, and the role lands on a value in each theme. Change the role and every component that reads it follows.

Colour

switchrow-fgSwitch with its label shown: the label.
text-primaryneutral-925#0b0a10
text-primaryneutral-0#ffffff

Space and shape

switch-width
its own value
40px
switch-height
its own value
24px
switch-radius
radius-full
9999px
switch-after-inset
inset-2xs
2px
switch-after-size
its own value
calc(24px - 2 * 2px)
switch-after-radius
radius-full
9999px
switch-after-on-translate-x
its own value
calc(40px - calc(var(--switch-height) - 2 * var(--switch-after-inset)) - 2 * 2px)
switch-after-active-scale-x
its own value
1.22
switch-after-on-active-translate-x
its own value
calc(calc(var(--switch-width) - var(--switch-after-size) - 2 * var(--switch-after-inset)) - calc(var(--switch-height) - 2 * var(--switch-after-inset)) * (1.22 - 1))
switch-after-on-active-scale-x
its own value
1.22
switch-disabled-opacity
opacity-disabled
0.35
switch-edge-width
line-strong
2px
switchrow-gap
gap-lg
12px
switchrow-words-gap
gap-2xs
2px
switchrow-hint-padding-y
inset-md
12px
switchrow-hint-border-bottom-width
line-hairline
1px
switchrow-end-gap
gap-lg
12px

Type

switchrow-font
text-caption
500 13px/18px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif
switchrow-hint-font-weight
text-label-weight
600
switchrow-hint-font-size
text-label-size
14px
Aa
switchrow-hint-line-height
text-label-line-height
20px
switchrow-words-small-font
text-caption
500 13px/18px "Funnel Sans", system-ui, -apple-system, "Segoe UI", sans-serif

Motion

switch-duration
motion-fast
160ms
switch-easing
ease-standard
cubic-bezier(0.2, 0, 0, 1)
switch-after-duration
motion-fast
160ms
switch-after-easing
ease-standard
cubic-bezier(0.2, 0, 0, 1)
switch-after-active-duration
motion-instant
100ms

Checked automatically with axe-core 4.11.4 against WCAG 2.2 A and AA, on the live preview above, in light and dark, on 26 October 2026.

Result
No issues found, in light or in dark.
By design
A switch named by label that Tab reaches; Enter or Space flips it through onChange, it is announced "on" or "off", and disabled takes it out of the tab order. With showLabel the whole row is its label, so a click on the text flips it too, and the hint is its description. Sliding the knob is for the pointer; Enter or Space does the same. In forced colours the track draws an edge and the knob a solid in the system colours (Highlight when on), and the switch keeps its size.
Not tested
The automated check doesn't test keyboard use, focus order or what a screen reader says. The lines above are the design system's own account of them.