Toggle

A button that stays pressed until it is clicked again.

Usage

Toggle is a Button that holds an on and off state. Pressed, it fills with the accent; unpressed, it looks like a secondary Button. Use it for a setting that applies as soon as it changes and reads as an action, such as showing a forecast line on a chart or marking a tariff as a favorite.

import { Toggle } from '@epilot/spark-ui/toggle'
function ForecastToggle() {
  return (
    <Toggle pressed={showForecast} onPressedChange={setShowForecast}>
      Show forecast
    </Toggle>
  )
}

For a setting in a form or a settings list, where a label sits next to the control, use Switch or Checkbox. For a row of related toggles, wrap them in a Toggle Group. For a one-off action with no state, use Button.

Examples

With an icon

An icon-only Toggle needs an aria-label. Icons scale with size like they do in Button.

Sizes

size takes the Button size scale, including the square icon-* sizes.

Styles and colors

styleVariant (solid, soft, surface) and color set the pressed look, like they do in Button. Unpressed, a Toggle is the neutral outline, or a neutral fill in a soft Toggle Group. color alone implies solid. Each row shows a style unpressed, then pressed.

Button's ghost and outline are not offered: pressed, they read weaker than the unpressed outline.

Check

Text-sized Toggles draw a check when pressed. Its room is always reserved: the label slides from the middle to make way for it, so the Toggle never resizes and neighbors in a group don't shift. Set showCheck={false} to remove it. Icon sizes never show a check.

Disabled

A disabled Toggle keeps its pressed or unpressed look at half opacity and ignores clicks.

Controlled

Pass pressed and onPressedChange to keep the state in your own component. Without onPressedChange updating pressed, clicks do nothing visible.

Forecast shown

API Reference

Toggle

Renders a Base UI Toggle as a <button>. Other Base UI props pass through.

PropTypeDefaultDescription
pressedboolean—Controlled pressed state. Provide onPressedChange to update it.
defaultPressedbooleanfalseInitial pressed state when uncontrolled.
onPressedChange(pressed: boolean, details) => void—Fires with the next pressed state on click, Enter, or Space.
disabledbooleanfalseIgnores interaction and dims the Toggle.
size"small" | "default" | "medium" | "icon-small" | "icon" | "icon-medium""default"Height, padding, and icon size, matching Button. Use an icon-* size for an icon-only Toggle.
styleVariant"solid" | "soft" | "surface"—The pressed look. Unpressed is the neutral outline, or a neutral fill in a soft Toggle Group. Defaults to solid when only color is set.
color"primary" | "neutral" | "destructive"—The pressed accent color, matching Button.
showCheckbooleantrueDraws a check when pressed. Never shown for icon-* sizes. In a group, defaults to the group's.
valuestring—Identifies the Toggle inside a Toggle Group. Required there, ignored outside one.
classNamestring—Merges with the base styles. Style the pressed state with the data-pressed: variant.

Accessibility

  • Toggle renders a native <button> with aria-pressed, so screen readers announce it as a toggle button and read its state.
  • Keep the label the same in both states. The pressed state is announced separately, so a label that flips ("Show forecast" to "Hide forecast") contradicts it.
  • Enter and Space toggle it, like any button.
  • Give an icon-only Toggle an aria-label.
  • The check that draws in on a pressed Toggle is decorative and aria-hidden. The state is announced by aria-pressed, not by the check. Icon sizes show no check.

On this page