Skip to content

Toggle

  • A formatting button in an editor: Bold, Italic
  • A mode that stays on: Mute, Pin
  • A group of options that apply at once: alignment, list or grid view — with ToggleGroup

Not for a setting in a form or a settings list — use a Checkbox or a Switch.

Choosing between rows of controls:

ComponentUse it forFor example
ToolbarSeveral controls acting on one thing, reached with one Tab stop and the arrow keysAn editor’s formatting bar
ToggleGroupA set of Toggles sharing one valueText alignment, bold / italic / underline
Buttons in a rowA few independent actions, each its own Tab stopCancel / Save at the end of a form

Choosing between Checkbox, Switch or Toggle:

ComponentUse it forFor example
CheckboxA yes/no choice, or one of several independent options, that applies when the form is submitted“I agree to the terms”, “Email me updates”
SwitchA setting that takes effect the moment it is flipped, with no Save button“Dark mode”, “Wi-Fi”, “Notifications on”
ToggleA button that stays pressed, usually in a toolbar, for a mode or formatting“Bold”, “Mute”, “Pin”
import { useState } from 'react';
import { Toggle, ToggleGroup } from '@arun-dev/ui';
export default function ToggleBasics() {
const [muted, setMuted] = useState(true);
const [align, setAlign] = useState<string[]>(['left']);
return (
<div
style={{ display: 'flex', flexWrap: 'wrap', gap: 'var(--space-md)', alignItems: 'center' }}
>
{/* The name stays "Mute notifications"; aria-pressed says whether it's on, and the
icon follows the same state. */}
<Toggle pressed={muted} onPressedChange={setMuted} aria-label="Mute notifications">
<span aria-hidden>{muted ? '🔕' : '🔔'}</span> Mute
</Toggle>
{/* One at a time: Tab reaches the pressed one, the arrow keys move along. */}
<ToggleGroup aria-label="Alignment" value={align} onValueChange={setAlign}>
<Toggle value="left">Left</Toggle>
<Toggle value="center">Center</Toggle>
<Toggle value="right">Right</Toggle>
</ToggleGroup>
<ToggleGroup aria-label="Style" multiple defaultValue={['bold']}>
<Toggle value="bold">B</Toggle>
<Toggle value="italic">I</Toggle>
<Toggle value="underline">U</Toggle>
</ToggleGroup>
</div>
);
}

Toggle is a <button aria-pressed>: a button that stays pressed, such as Mute or Bold. Screen readers say “pressed” or “not pressed”.

To show the state in the content too, as the bell does, control the Toggle with pressed and onPressedChange and pick the icon from the same state. Keep the name the same in both states (“Mute notifications”): aria-pressed already says whether it’s on, and a name that changed to “Unmute” would describe the opposite action.

ToggleGroup holds the values of its pressed Toggles:

  • One at a time by default: pressing one releases the others, and pressing the pressed one releases it.
  • Several with multiple.
  • One Tab stop: Tab reaches the pressed Toggle (or the first), and the arrow keys move along, skipping disabled ones.
<ToggleGroup aria-label="Alignment" value={align} onValueChange={setAlign}>
<Toggle value="left">Left</Toggle>
<Toggle value="center">Center</Toggle>
</ToggleGroup>

Inside a Toolbar, a ToggleGroup’s Toggles join the toolbar’s arrow keys.

Toggle props
PropTypeDefaultDescription
pressedbooleanControlled state. Provide onPressedChange alongside it.
defaultPressedbooleanfalseInitial state when uncontrolled.
onPressedChange(pressed: boolean) => voidCalled on every press.
valuestringIts value in a ToggleGroup: pressed while the group holds it.
disabledbooleanfalseNot pressable, and skipped by the arrow keys.
classNamestringConcatenated with the component's own classes, never replacing them.
renderReactElementElement or component to render instead of the default. Props, className, event handlers and ref are merged onto it.
refRef<HTMLElement>Ref to the rendered element. Merged with any ref on the render element.
…restHTMLAttributesAnything else is spread onto the rendered element, so id, aria-*, data-* and event handlers all reach the DOM.
ToggleGroup props
PropTypeDefaultDescription
valuestring[]Controlled: the pressed Toggles' values.
defaultValuestring[][]Initial value when uncontrolled.
onValueChange(value: string[]) => voidCalled on every press.
multiplebooleanfalseLets more than one be pressed. Without it, pressing one releases the others.
disabledbooleanfalseDisables every Toggle.
orientation'horizontal' | 'vertical''horizontal'Which arrow keys move between the Toggles.
classNamestringConcatenated with the component's own classes, never replacing them.
renderReactElementElement or component to render instead of the default. Props, className, event handlers and ref are merged onto it.
refRef<HTMLElement>Ref to the rendered element. Merged with any ref on the render element.
…restHTMLAttributesAnything else is spread onto the rendered element, so id, aria-*, data-* and event handlers all reach the DOM.
  • A choice that’s on or off in a form, such as “Email me updates”, is a Switch or a Checkbox. A Toggle is for actions and view states.
  • Restyle with the --toggle-* tokens.