DEV Community

Cover image for shadcn's switch toggles one setting, so give each switch a label readers see
Dave Kurian
Dave Kurian

Posted on Originally published at otf-kit.dev

shadcn's switch toggles one setting, so give each switch a label readers see

A settings toggle looks simple, and most of the work is in its label. shadcn's switch is a checked and unchecked control, and its page pairs it with a Field and a FieldLabel, so the label is part of what you ship.

What the shadcn page covers

The page describes the component as "A control that allows the user to toggle between checked and not checked." The install command is pnpm dlx shadcn@latest add switch, with tabs for npm, yarn and bun. The usage section imports Switch from @/components/ui/switch. The basic example also imports Label.

The form examples import Field, FieldGroup and FieldLabel from @/components/ui/field. The page says to "Add the aria-invalid prop to the Switch component to indicate an invalid state," and to "Add the data-disabled prop to the Field component for styling." Its API reference says "See the Base UI Switch documentation," but the installed source imports the switch from radix-ui, so the checked-state props below are the Radix Switch props that the component passes through: checked, defaultChecked and onCheckedChange.

The examples cover an airplane mode toggle, a description variant ("Share across devices"), a choice card, a disabled state, an invalid state, two sizes and a right-to-left layout. Our capture of the page cut off its form markup, so the code below uses the parts the page names, and the checked-state props come from the Radix Switch the installed source wraps. Check the View Code panel before you copy the markup. The rules below are ours, and they are labelled as ours.

Build a labeled settings toggle

A switch with no label tells the reader that something can change, but not what. Pair every switch with a FieldLabel that names the setting, and point the label at the switch with the same id.

The snippet below is adapted from shadcn's Switch example, in the shadcn-ui/ui repository at apps/v4/examples/radix/switch-demo.tsx and apps/v4/registry/bases/radix/examples/switch-example.tsx. Its Airplane Mode example pairs a switch with an id and a label with htmlFor pointing at it, and the snippet keeps that pairing. The examples contain no form element, so the snippet does not add one. Wrap it in your own form.

import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"
import { Switch } from "@/components/ui/switch"

export function EmailUpdatesSetting({
  checked,
  onChange,
}: {
  checked: boolean
  onChange: (value: boolean) => void
}) {
  return (
    <FieldGroup>
      <Field>
        <FieldLabel htmlFor="email-updates">Email updates</FieldLabel>
        <Switch
          id="email-updates"
          checked={checked}
          onCheckedChange={onChange}
        />
      </Field>
    </FieldGroup>
  )
}
Enter fullscreen mode Exit fullscreen mode

The label says what the setting is, not what the switch does. "Email updates" names the setting. "Enable" alone does not, because the reader has to guess what it turns on. The htmlFor and the id must match, so clicking the label flips the switch and a screen reader announces the label with the state.

A close view of a toggle in its on position, with a stylus tip resting on the knob

Choose a switch over a checkbox

Our rule is that a switch changes a setting right away, and a checkbox waits for the form to be submitted. If the change takes effect when the reader flips it, use a switch. If the reader can change several answers before they save, a checkbox fits better, because nothing takes effect until the submit.

Keep the rule the same across the product. A switch that sometimes saves immediately and sometimes waits for a Save button teaches the reader to check every page twice.

Say when the change takes effect

When a switch saves immediately, show a short confirmation. A toast works for that, because the message is about a completed action. When the switch waits for a submit, say so in the description, such as "Changes apply when you save." The reader should never have to guess whether a flip has taken effect.

The page's description variant pairs the label with a line of explanation. Use that line for the effect, such as what a reader will see differently, rather than repeating the label.

Dex and Luna at a split panel: a toggle off on one side, the same toggle on the other

Mark invalid and disabled states

The page's invalid example puts aria-invalid on the Switch, and its disabled example puts data-disabled on the Field so the styling can follow. Use the disabled state when the setting is locked by a plan or a rule, and say why in the text next to it. A disabled switch with no reason looks broken to the reader.

Use the invalid state sparingly. A switch rarely fails on its own, so the invalid state usually belongs to a setting that depends on another one, such as a notification switch that needs an email address first.

Group related switches

Put related switches under one heading, so the reader sees which settings belong together. Put the setting most people change first, and keep the order the same on every visit. A switch that moves between page loads confuses readers who have learned where it sits, and a group with ten switches needs a second heading so the reader can scan it.

Test the keyboard, the label and the phone

Check these on the real settings page:

  • Tab to the switch. The focus ring should show on the switch, not on the label.
  • Press Space. The switch should toggle, and the state should change on screen.
  • Click the label text. The switch should toggle, because the label points at it.
  • Read the switch with a screen reader. It should announce the label and whether the switch is on or off.
  • On a 390px phone, check that the tap target is large enough to hit with a thumb and that the label wraps without pushing the switch off the row.

Run the phone check last, after the label wording is final. A long label can wrap and leave the switch on its own line, which makes the pairing harder to see.

Where OTF stands

If you want a settings toggle already built into a product, we cannot point you to one. We checked the SaaS Dashboard, Booking, Fitness and Arcade kit pages for switch, toggle and radio terms, and none names a switch component. Each of those pages links a Toggle Button block in its navigation. That is a link to a component page, not a switch in the kit, and this article does not say a kit ships one.

The pricing page lists the Full-stack kits at $99 each and the Everything Bundle at $149, both as one-time payments, and it offers a live demo before you buy. Check each kit's repository for the form controls it ships before you rely on any of them. For a choice that needs exactly one answer rather than an on or off, see the radio group guide, and for a settings panel that opens from the edge, see the dialog and sheet guide. If you are choosing a starting point for a product, the pricing page is the place to compare kits side by side: OTF pricing.

Sources

Top comments (0)