Skip to content
View as Markdown

Inputs

Switch

An on/off toggle for a single setting that takes effect immediately.

Import

TSX
import { Field, Switch } from "@loamui/core";

Usage

Every example has a CSS tab. That’s the real, complete stylesheet for the component: plain, static CSS, with nothing running in the browser.

Basic usage

A bare Switch named by aria-label, for a row where the words already sit beside it. Off by default: a setting the user has not turned on.

Checked

The track fills with the primary colour when on.

Label position

Place the text before or after Switch.Root inside Field.Label. DOM order sets the label position.

Label at the end (default)
Label at the start

Disabled

disabled reaches the native input: the track is dimmed and the input is skipped by Tab, and a switch that is on and disabled shows a setting that is on and not the user's to change here. Disabled is detected on the input, never declared on the row.

Composed inside a Field

The bare Switch.Control self-wires from Field context: label association and description linking come from the Field, the same composition contract every form control shares.

Sent at most once a day.

Guidance

When to use it

  • For an instant on/off setting that takes effect immediately, with no separate save step (notifications, dark mode).
  • When the two states are clearly opposite and the control acts like a physical switch.

When not to

  • When the change only applies after submitting a form. Use a Checkbox instead: its ticked state reads as "will apply when I submit".
  • For selecting among more than two states. Use Radio or Select.

Accessibility

  • Renders a native checkbox exposed with role="switch", so it is operable by keyboard and announced as on/off.
  • The label is tied to the control; the whole row is clickable.
  • In the rare case a switch needs an error message, wrap it in a Field.Root and add a Field.Error before the control: set invalid on Field.Root for the validation state; the message is announced.
  • State is conveyed by more than colour (the thumb position), so it remains clear in forced-colors and for colour-blind users.
  • Disabled is detected on the native input (:has(input:disabled) on the row, input:disabled on the track), never declared on a wrapper.

How it works

A switch acts now, a checkbox acts on submit

role="switch" announces on/off, and users expect flipping it to take effect immediately, like a light switch. Inside a form that applies changes on save, that expectation is a lie: use Checkbox, whose ticked state reads as “will apply when I submit”. The test is the presence of a save button: if there is one, it isn't a Switch.

Label the affirmative

The label names the thing that is on when the switch is on: “Email notifications”, never “Disable emails”. The control already says on or off, so a negated label makes on mean off. Keep the label constant across states; a label that rewrites itself when toggled leaves users unsure whether it describes the current state or the action.

Parts

Switch.Root

A span containing Control and Track. Native span props and ref are forwarded.

Switch.Control

The native checkbox with role=switch. Receives checked, defaultChecked, disabled, name, onChange, ref and other input props, and self-wires from Field.

Switch.Track

The decorative track, following the Control in the DOM. Native span props are forwarded.

Switch.Thumb

The decorative thumb inside Track; CSS moves it in response to the native input’s checked state.