Skip to content

SwitchForm

A Switch that saves itself: optimistic with JavaScript, a plain form POST without.

FormsIsland

Examples

Row switch

The thumb flips at once and a spinner shows while the request is in flight; clicks are ignored until it answers. An error flips it back and shows a toast.

Example
<SwitchForm
  action={routes.dashboard.servers.toggle.href({ id })}
  name="enabled"
  checked={server.enabled === 1}
  fields={{ return_to: serversHref }}
  aria-label={`Route ${server.display_name}`}
  subject={server.display_name}
/>

Usage

Usage
import { SwitchForm } from '@switchboard/ui'

// The action answers JSON to Accept: application/json: { checked } (2xx) or { message } (error).
// Without JavaScript the same form posts and the action redirects (to return_to).
<SwitchForm action={toggleHref} name="enabled" checked={on} fields={{ return_to: listHref }} aria-label="Route Linear" />

Props

Every component also takes mix, for css() and mixins applied after its own style.

SwitchForm

SwitchForm props
PropTypeDefaultDescription
action*string–Where the form posts.
name*string–Field name. Posts "off", then "on" when on.
checked*boolean–Server state. Adopted when it changes and nothing is in flight.
fieldsRecord<string, string>–Hidden fields, e.g. { return_to } for the no-JS redirect.
labelstring–Inline label.
aria-labelstring–Name when there is no label.
size'sm' | 'md''sm'Switch size.
subjectstring–Named in the error toast: "Couldn't switch off Linear".
submitLabelstring'Save'The button shown only without JavaScript.

Accessibility

  • In flight the input is read-only, not disabled, so focus stays on it; the label gets aria-busy.
  • Errors are announced by the toast region, since focus stays on the switch.
  • Without JavaScript a Save button appears (noscript) and the form posts normally.

Guidance

Do

  • Use for reversible, predictable settings.
  • Answer the JSON request without a redirect or flash.

Don’t

  • Use for destructive changes; use a ConfirmDialog.
  • Navigate after the toggle; the page reloads its data quietly.