MobTranslate styleguide

Toggle

Expose a stable named pressed action and make its local effect visible.

A pressed action

Use Toggle for a two-state action such as emphasis or showing a local layer. Keep its label stable; aria-pressed conveys the state. Use Switch for a feature setting and Checkbox for an independent form option.

A pressed visual state is not a native checkbox form field. If a form needs this value, serialize and validate it explicitly in the consuming task.

Anatomy and specifications

PartActual CSS / semantics
RootNative button and HTMLButtonElement ref
TargetMinimum 44px height; wrapping text; 12px inline padding
Surface2px border, --radius-md, --text-sm weight 500
PressedPrimary fill/foreground and aria-pressed
Hover / focusMuted hover surface; token ring
UnavailablePrimitive disabled behavior and visible unavailable state

Working local emphasis

This English-only sample changes its actual local emphasis.

Local emphasis off.

tsx
'use client';
import { useState } from 'react';
import { Button, Toggle, ToggleGroup, ToggleGroupItem } from '@mobtranslate/ui';

export function ToggleSelectionExample() {
  const [pressed, setPressed] = useState(false);
  return <div data-toggle-lab className="space-y-4"><Toggle pressed={pressed} onPressedChange={setPressed} className={state => state.pressed ? 'local-toggle-on' : 'local-toggle-off'}>Emphasize local example</Toggle><p style={{ fontWeight: pressed ? 700 : 400 }}>This English-only sample changes its actual local emphasis.</p><Toggle disabled>Unavailable emphasis</Toggle><p role="status">Local emphasis {pressed ? 'on' : 'off'}.</p></div>;
}

export function ToggleGroupSelectionExample() {
  const [multiple, setMultiple] = useState(false);
  const [value, setValue] = useState<string[]>(['title']);
  const [vertical, setVertical] = useState(false);
  return <div data-toggle-group-lab className="space-y-4">
    <Button type="button" variant="outline" aria-pressed={multiple} onClick={() => { setMultiple(current => !current); setValue([]); }}>Allow multiple local segments</Button>
    <Button type="button" variant="outline" aria-pressed={vertical} onClick={() => setVertical(current => !current)}>Use vertical local segments</Button>
    <ToggleGroup multiple={multiple} value={value} onValueChange={setValue} orientation={vertical ? 'vertical' : 'horizontal'} aria-label="Local reading sections" className={state => state.multiple ? 'local-segments-multiple' : 'local-segments-single'}>
      <ToggleGroupItem value="title">Title section</ToggleGroupItem><ToggleGroupItem value="notes">Notes section</ToggleGroupItem><ToggleGroupItem value="unavailable" disabled>Unavailable section</ToggleGroupItem>
    </ToggleGroup>
    <div data-local-sections>{value.includes('title') && <h3 className="font-semibold">Local title section</h3>}{value.includes('notes') && <p>English-only local notes section.</p>}{value.length === 0 && <p>No local sections selected.</p>}</div>
    <p role="status">Pressed local sections: {value.join(', ') || 'none'}. {multiple ? 'Multiple choices permitted.' : 'At most one; empty is allowed.'}</p>
  </div>;
}

API reference

PropContract
pressed / defaultPressedControlled boolean / initial state; false default.
onPressedChange(boolean, eventDetails); update actual state.
disabledfalse; primitive guards activation.
valueString identity when used in a ToggleGroup.
children / native button props / render / refStable accessible label and forwarded button semantics.
className / style / render / native propsInstalled primitive props; styled wrappers retain string-or-state class callbacks. A custom render must preserve semantics, events and refs.

Behavior and failures

  • Space/Enter activate the native button; focus remains on it while its pressed state changes.
  • Do not change a stable action name into an unrelated command after pressing. Express the selected result through state and nearby content.
  • Disabled must prevent both the callback and the effect, not merely dim the surface.
  • Use explicit serialization for real form/request state; pressing a toggle is not a save receipt.
  • An icon-only toggle needs a meaningful accessible name and enough target area.

Verification and release scope

  • Check actual names, roles, state and focus with pointer and keyboard. Inspect the retained value and submitted FormData when relevant.
  • Exercise empty, selected, mixed, disabled, read-only, invalid and pending/recovery states that apply to the control. Styling alone does not prove enforcement.
  • Check both themes, long labels, 320px reflow, meaningful graphic/text contrast, reduced motion, forced colors and the actual target device.
  • Use a named screen-reader/browser pair to verify spoken state. DOM assertions and local examples do not prove announcements or backend persistence.
  • Selection never establishes language quality, source authority, consent, qualified review or permission. Keep that evidence explicit in the product task.