The Toggle component renders a switch to toggle between enabled or disabled states.

Toggle

Usage

  • Use Toggle for a setting or feature that takes effect immediately, with no form submission.
  • Use Checkbox instead when the user selects zero or more options to submit to a form.
  • Never treat Toggle and Checkbox as interchangeable — Toggle is an on/off switch, Checkbox is an independent selection.
  • Set the default state (isChecked) to the safest or most common option. Never enable a destructive or data-sharing setting by default.

Appearance

  • size="md" — the default. Use in the majority of contexts, including settings pages and form layouts.
  • size="sm" — use in tighter layouts such as table rows, inline controls, or condensed settings panels.
  • size="xs" — use in the most space-constrained contexts.

Behaviors

  • Base — the unchecked track uses a neutral surface color; the checked track uses the active accent color.
  • Hover — the track background darkens. No prop controls this.
  • Focus — the track receives the standard 2px focus ring. No prop controls this.
  • Disabled (isDisabled) — blocks interaction and drops the accent color. A disabled checked Toggle keeps a stronger fill than a disabled unchecked one so its state stays readable.
  • Truncation (withTruncatedLabel, default true) — labels clip with an ellipsis when they overflow. Set withTruncatedLabel={false} to let the label wrap to multiple lines.

Content

  • Phrase the label (label) around what happens when the Toggle is turned on, never around what is prevented when it is off — negative phrasing creates a double-negative in the off state.
  • Write labels that are self-explanatory without surrounding context.
  • Use description to add context the label alone doesn't convey. Keep it to a short phrase with no end punctuation.
  • Never restate the label in the description — add new information.
  • Frame error messages as an actionable step the user can take to resolve the issue.

Implementation Notes

  • Toggle is fully controlled. Pass isChecked and update it from onChange; without that update the input re-syncs to the previous state.
  • Provide label, ariaLabel, or ariaLabelledby — the component throws an accessibility error when all three are missing. shouldValidateLabelPresence={false} suppresses that check when labeling is handled externally.
  • onChange receives a React ChangeEvent<HTMLInputElement> in React and a native Event in Ember. It does not fire while isDisabled is set.
  • Rich content — React accepts a ReactNode for label, description, and error in place of a string. Ember takes @label as a string or a :label named block, which wins over the arg.
  • The label always renders before the track; toggle position is fixed and not consumer-configurable.
  • withCenterBaseline aligns the track to the center baseline of the label's first line instead of the default baseline alignment.
  • name groups Toggles that share a form name and falls back to id when omitted; value sets the input's value attribute.
  • Mark validation state with isInvalid alongside the error message.
  • Deprecated — never use labelOn or labelOff (labels inside the track are no longer supported), and use size="md" / size="sm" instead of the "medium" / "small" aliases.
  • Style hooks — unsafe_fieldClassName, unsafe_inputClassName, unsafe_labelClassName, unsafe_descriptionClassName, unsafe_errorClassName, and unsafe_footerClassName target individual parts.
  • Ember invocation: <PlumaToggle @isChecked={{this.isOn}} @onChange={{this.handleChange}} @size="sm" /> with @-prefixed args.

On this page