Skip to content

Components · Forms

SwitchSettingsList

On/off settings that each save on their own, with saving, error and retry per row.

@rookcom/monarch-reactComponent

Notification preferences

Security notifications

Emails about activity on your account.

  • Password changes and new recovery methods.

  • When your account is used on a device for the first time.

Usage examples

Failed save, rollback and retry

Purpose

Shows a group of on/off preferences, such as notification or privacy settings, where each switch saves immediately. Every row has its own saving, saved and failed state, so one failure never hides behind a page-level toast.

Use when

  • Each toggle is persisted on its own (a PATCH per preference) rather than with a form Save button.
  • Saves can fail and the user must see which setting did not stick.

Avoid when

  • Switches are submitted together with other fields: use Field with layout="row" and a Switch inside a form.
  • A single setting with no group: a Switch with label and description, or SettingsRow.

Design principles

  • Optimistic: the switch moves at once and rolls back only if the save fails.
  • Status lives on the row it belongs to: a spinner while saving, a brief "Saved", or the error with Retry.
  • Results are announced, not only shown, so screen-reader users hear "Saved" or the error.
  • No data fetching: the product passes checked and an onCheckedChange that returns its save promise.

API reference

import { SwitchSettingsItem, SwitchSettingsList } from '@rookcom/monarch-react';
ExportKindRenderingRoot class
SwitchSettingsItemcomponentclient.mn-switch-settings-
SwitchSettingsListcomponentclient.mn-switch-settings-

SwitchSettingsList renders a <div> (role group when it has a title or label) with an optional heading and a <ul> of rows; the ref goes to the <div>.

SwitchSettingsItem renders an <li> (ref) with the label, description, status and a Monarch Switch.

Status wording (labels: saving, saved, error, retry), savedDuration and getErrorMessage are set on the list and can be overridden per row.

Generated from the TypeScript declarations of packages/react/src/components/forms/switch-settings-list.

Properties

SwitchSettingsItem

One setting row: label and description on the left, the switch and its save status on the right.

PropTypeDescription
label requiredReactNodeThe setting's name. Labels the switch.
checkedbooleanThe saved state (controlled).
childrenReactNode
classNamestring
defaultCheckedbooleanThe initial saved state (uncontrolled).
descriptionReactNodeWhat the setting does. Describes the switch.
disabledboolean
idstring
labelsSwitchSettingsLabelsOverride the list's status wording for this row.
onCheckedChange((checked: boolean) => void | Promise<void>)Saves the new state. The switch moves at once; return a promise to show "Saving" and then "Saved", or reject it to roll the switch back and show the error with a retry button.
onStatusChange((status: SwitchSettingsStatus) => void)Called whenever the row's save status changes.

SwitchSettingsList

A group of on/off settings that each save on their own, such as notification preferences. Rows toggle optimistically, show their own saving and error state with retry, and roll back if the save fails.

PropTypeDescription
children requiredReactNodeSwitchSettingsItem rows.
classNamestring
descriptionReactNodeA sentence under the title.
getErrorMessage((error: unknown) => ReactNode)Turns a failed save into a message shown after `labels.error`. Default: the Error's message.
headingLevel"h2" | "h3" | "h4" | "h5" | "h6"Heading element for `title`. Default `h3`.
idstring
labelsSwitchSettingsLabelsStatus wording for every row (rows can override).
savedDurationnumberHow long "Saved" stays visible, in ms. Default 2000.
titleReactNodeGroup heading, for example "Email notifications". Names the group.

Variants

One visual form: a bordered list of rows. Wording is configurable through labels for translation.

States

StateExposed asBehaviour
Idledata-status="idle"The switch shows the saved value.
Savingdata-status="saving", aria-busy="true" on the switchThe switch already shows the new value; a spinner named "Saving" sits beside it and further toggles are ignored until the save settles.
Saveddata-status="saved"A check and "Saved" for savedDuration (2 s), announced politely. Only when onCheckedChange returned a promise.
Errordata-status="error"The switch rolls back, the error shows under the label and is announced, and a Retry button repeats the failed value.
Disableddata-disabled, disabled on the switchDisabled text colour; the switch cannot be toggled.

Interaction behaviour

  • Toggling calls onCheckedChange(next) with the switch already moved.
  • Resolved promise: "Saved" appears and clears. Rejected: the switch returns to its previous value and the row shows the error and Retry.
  • Retry calls onCheckedChange again with the value that failed. Toggling the switch again also retries.
  • Uncontrolled rows (defaultChecked) keep the new value after a successful save. Controlled rows (checked) show the optimistic value until the parent’s checked changes, and always follow a new checked when nothing is saving.
  • onStatusChange(status) reports each row’s status, for example to block navigation while saving.

Keyboard support

KeysAction
TabMoves between switches, and to a row’s Retry button when shown.
Space / EnterToggles the focused switch; activates Retry.

Accessibility

Role
group (list), switch (each row)
Accessible name
The list is named by title (or aria-label); each switch by its row label.
  • The row description is the switch’s accessible description; while a save has failed, the error is added to it.
  • Each row has a polite role="status" region that announces "Saved" or the error. The saving spinner is a named status.
  • Retry is named "Retry {label}", so several failed rows stay distinguishable.
  • Rows are list items in a <ul>, so the number of settings is announced.

Responsive behaviour

  • Label and description wrap; the switch and status stay on the right.
  • Below 480px a row may wrap so a long status or the Retry button moves under the text, with no horizontal scrolling at 320px.

Theme support

  • Surface, borders and text are semantic tokens, so light, dark and more-contrast themes apply automatically.
  • "Saved" uses --mn-color-success-strong and errors --mn-color-danger-strong, both readable on the surface in every theme; the switch track follows the product accent.
  • The "Saved" fade uses the duration tokens, which are zero under reduced motion.

Do and don't

Do

  • Return the save promise from onCheckedChange; that is what drives the states.
  • Reject with an Error whose message tells the user what to do.
  • Group related settings under a title, one list per group.

Don't

  • Do not also show a toast for each save; the row already reports it.
  • Do not use it inside a form that has its own Save button.
  • Do not resolve the promise when the save failed.
  • Switch: The control used in each row.
  • SettingsSection: Card of mixed settings with one Save footer.
  • Field: layout="row" for a single switch row inside a form.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsSpinner, Switch

Testing coverage

  • A titled, described group of list items; switches are labelled and described by their rows.
  • Uncontrolled: Space toggles optimistically, aria-busy and a "Saving" status while pending, toggles during a save are ignored, "Saved" is announced and clears after savedDuration.
  • Failure: rolls back, the error describes the switch and is announced, "Retry {label}" repeats the failed value, and onStatusChange reports saving → error → saving → saved.
  • Controlled: keeps the optimistic value until the parent updates, then follows the parent.
  • A synchronous handler toggles without a "Saved" state; disabled rows do not toggle; aria-label names the group.
  • Labels and error messages can be set per list and per row.
  • Renders on the server.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery; Cross-browser axe: /components/switch-settings-list

Tests: packages/react/src/components/forms/switch-settings-list