Monet
@etched/monet 0.0.1

Switch

Ported

Turns one setting on or off, at once or in a settings form that saves with a button. For a choice among a form's other answers (agree, include), use a Checkbox. readOnly shows the value without a way to change it. Native attributes and ref go to the switch.

Kumo source
import { Switch } from "@etched/monet/switch";

export function Preview() {
  return <Switch label="Email alerts" defaultChecked />;
}

Installation

import { Switch, SwitchGroup, SwitchItem, SwitchLegend } from "@etched/monet/switch";

Examples

States

readOnly shows the value without a way to change it: off, the track is the read-only fill inside an edge.

import { Switch } from "@etched/monet/switch";

export function States() {
  return (
    <div className="row">
      <Switch aria-label="Off" />
      <Switch aria-label="On" defaultChecked />
      <Switch aria-label="Disabled" disabled />
      <Switch aria-label="Disabled and on" disabled defaultChecked />
      <Switch aria-label="Neutral" variant="neutral" />
      <Switch aria-label="Neutral and on" variant="neutral" defaultChecked />
      <Switch aria-label="Read-only" readOnly />
      <Switch aria-label="Read-only and on" readOnly defaultChecked />
    </div>
  );
}

Sizes

import { Switch, type SwitchSize } from "@etched/monet/switch";

const sizes: SwitchSize[] = ["sm", "base", "lg"];

export function Sizes() {
  return (
    <div className="row">
      {sizes.map((s) => (
        <Switch key={s} size={s} label={s} defaultChecked />
      ))}
    </div>
  );
}

Labels

import { Switch } from "@etched/monet/switch";

export function Labels() {
  return (
    <div className="grid">
      <Switch label="Break down by full-time and internship" />
      <Switch label="Label first" controlFirst={false} defaultChecked />
      <Switch label="Send a weekly digest" required={false} />
      <Switch label="LinkedIn sending (not configured)" disabled />
    </div>
  );
}

Saving

loading while a change saves: an arc turns on the knob, the switch keeps focus, and a second click waits until the save ends.

import { useState } from "react";
import { Switch } from "@etched/monet/switch";

export function Saving() {
  const [on, setOn] = useState(false);
  const [saving, setSaving] = useState(false);

  return (
    <div className="grid">
      <Switch
        label="Sync to LinkedIn"
        checked={on}
        loading={saving}
        onCheckedChange={(next) => {
          setOn(next);
          setSaving(true);
          setTimeout(() => setSaving(false), 1000);
        }}
      />
      <Switch label="Saving" defaultChecked loading />
    </div>
  );
}

Groups

Notifications

Changes save at once.

Bench controls (locked)
import { SwitchGroup, SwitchItem } from "@etched/monet/switch";

export function Groups() {
  return (
    <div className="grid">
      <SwitchGroup legend="Notifications" description="Changes save at once.">
        <SwitchItem label="Run finished" defaultChecked />
        <SwitchItem label="Run failed" defaultChecked />
        <SwitchItem label="Weekly digest" />
      </SwitchGroup>
      <SwitchGroup legend="Bench controls (locked)" disabled>
        <SwitchItem label="Auto-drain" defaultChecked />
        <SwitchItem label="Night mode" />
      </SwitchGroup>
    </div>
  );
}

In a field

Sent to the run owner when a run fails.

import { Field } from "@etched/monet/field";
import { Switch } from "@etched/monet/switch";

export function InAField() {
  return (
    <div className="grid">
      <Field label="Email alerts" description="Sent to the run owner when a run fails.">
        <Switch defaultChecked />
      </Field>
    </div>
  );
}

Accessibility

  • Space or Enter toggles it. A click on its label toggles it too.
  • A switch with aria-checked, named by label or aria-label, and described by its description and error. In a Field, the Field's label names it and its help describes it.
  • While loading, it has aria-busy, keeps focus, and a second toggle waits. readOnly sets aria-readonly, and disabled sets aria-disabled.
  • Without label, give it an aria-label. Without legend, give a SwitchGroup a SwitchLegend or an aria-label.
  • Use it for an on/off setting, at once or in a settings form that saves with a button. For a choice among a form's other answers (agree, include), use a Checkbox.

API reference

SwitchGroup

PropTypeDefaultDescription
classNamestring–Class on the outer element, for layout.
legendReactNode–Title of the group. Without it, add a legend child or an aria-label.
children *ReactNode–SwitchItem children, and optionally a SwitchLegend.
descriptionReactNode–Help text below the group. Hidden while an error shows.
errorFieldError–Error below the group. It marks every control in it invalid.
controlFirstbooleantrueDefault controlFirst of every item.
requiredboolean–false adds the optional marker after the legend.
disabledboolean–Turns off every switch in the group.
renderReactElement–The Base UI group the fieldset renders as.

SwitchItem

PropTypeDefaultDescription
labelTooltipReactNode–More about the field, behind an info button after the label.
labelTooltipLabelstring"More information"Names the info button.
descriptionReactNode–Help text below the control. Hidden while an error shows.
errorFieldError | FieldShortcuts["error"]–A message under the switch; it marks it invalid.
variant"default" | "neutral""default"
requiredboolean–false adds the optional marker after the label.
controlFirstbooleantrueSwitch before the label. false puts the label first. Inside a SwitchGroup, the group sets the default.
size"sm" | "base" | "lg""base"
loadingboolean–While a change saves: the knob shows a turning arc, the switch is busy (aria-busy, data-loading), and a second toggle waits. It keeps focus, unlike disabled.
classNamestring–Class on the outer element, for layout.
label *ReactNode–

SwitchLegend

PropTypeDefaultDescription
classNamestring–

Switch

PropTypeDefaultDescription
labelReactNode–Visible label. Without one, give the control an aria-label.
labelTooltipReactNode–More about the field, behind an info button after the label.
labelTooltipLabelstring"More information"Names the info button.
descriptionReactNode–Help text below the control. Hidden while an error shows.
errorFieldError | FieldShortcuts["error"]–A message under the switch; it marks it invalid.
variant"default" | "neutral""default"
requiredboolean–false adds the optional marker after the label.
controlFirstbooleantrueSwitch before the label. false puts the label first. Inside a SwitchGroup, the group sets the default.
size"sm" | "base" | "lg""base"
loadingboolean–While a change saves: the knob shows a turning arc, the switch is busy (aria-busy, data-loading), and a second toggle waits. It keeps focus, unlike disabled.
classNamestring–Class on the outer element, for layout.