Siteplane UI

Switch

Turn a setting on or off.

Markdown
"use client";

import { Label } from "@/siteplane/components/label";
import { Switch } from "@/siteplane/components/switch";

export default function Example() {
  return (
    <Label>
      <Switch />
      Marketing emails
    </Label>
  );
}

Installation

pnpm dlx shadcn@4.18.0 add @siteplane/switch

Complete the one-time setup first. Registry JSON lists source files and dependencies.

For this page’s examples, also install:

pnpm dlx shadcn@4.18.0 add @siteplane/button @siteplane/form @siteplane/input @siteplane/label

Field is installed with Input.

Usage

import { Label } from "@/siteplane/components/label";
import { Switch } from "@/siteplane/components/switch";

<Label>
  <Switch />
  Marketing emails
</Label>;

With description

Place a FieldLabel and a FieldDescription before the switch, inside a Field. The Field connects both to the switch, which sits at the end of the row, centered on it.

Save changes to documents as you type.

"use client";

import {
  Field,
  FieldDescription,
  FieldLabel,
} from "@/siteplane/components/field";
import { Switch } from "@/siteplane/components/switch";

export default function Example() {
  return (
    <Field className="w-full max-w-sm flex-row items-center justify-between gap-4">
      <div className="grid gap-1">
        <FieldLabel>Auto-save</FieldLabel>
        <FieldDescription>
          Save changes to documents as you type.
        </FieldDescription>
      </div>
      <Switch defaultChecked />
    </Field>
  );
}

Disabled and invalid

disabled blocks interaction and leaves the value out of form data. aria-invalid only applies the invalid style; it does not validate.

"use client";

import { Label } from "@/siteplane/components/label";
import { Switch } from "@/siteplane/components/switch";

export default function Example() {
  return (
    <div className="grid gap-3">
      <Label>
        <Switch disabled />
        Usage analytics
      </Label>
      <Label>
        <Switch defaultChecked disabled />
        Security alerts
      </Label>
      <Label>
        <Switch aria-invalid />
        Accept terms and conditions
      </Label>
    </div>
  );
}

Card style

Wrap the text and the switch in Label variant="card" so the whole card toggles the setting. Label owns the shared hover, checked and disabled styles.

"use client";

import { Label } from "@/siteplane/components/label";
import { Switch } from "@/siteplane/components/switch";

export default function Example() {
  return (
    <Label
      variant="card"
      className="flex w-full max-w-sm items-center justify-between"
    >
      <span className="flex flex-col gap-1">
        <span>Enable notifications</span>
        <span className="text-muted-foreground text-xs">
          You can enable or disable notifications at any time.
        </span>
      </span>
      <Switch defaultChecked size="sm" />
    </Label>
  );
}

Controlled state

Pass checked with onCheckedChange when your application owns the value; otherwise use defaultChecked.

"use client";

import { useState } from "react";
import { Label } from "@/siteplane/components/label";
import { Switch } from "@/siteplane/components/switch";

export default function Example() {
  const [checked, setChecked] = useState(false);
  return (
    <Label>
      <Switch checked={checked} onCheckedChange={setChecked} />
      Show completed tasks
    </Label>
  );
}

Form integration

Inside a Field, the switch uses the field’s name and submits its value (on when none is set) only while it is on, unless you set uncheckedValue.

"use client";

import { Button } from "@/siteplane/components/button";
import { Field, FieldLabel } from "@/siteplane/components/field";
import { Form } from "@/siteplane/components/form";
import { Switch } from "@/siteplane/components/switch";

export default function Example() {
  return (
    <Form
      className="grid w-full max-w-sm gap-4"
      onSubmit={(event) => {
        event.preventDefault();
      }}
    >
      <Field name="marketing">
        <FieldLabel>
          <Switch defaultChecked />
          Enable marketing emails
        </FieldLabel>
      </Field>
      <Button type="submit">Save preferences</Button>
    </Form>
  );
}

Sizes

Omit size to inherit the provider’s control size.

"use client";

import { Label } from "@/siteplane/components/label";
import { Switch } from "@/siteplane/components/switch";

const sizes = [
  ["sm", "Small"],
  ["md", "Medium"],
  ["lg", "Large"],
  ["xl", "Extra large"],
] as const;

export default function Example() {
  return (
    <div className="flex flex-wrap gap-4">
      {sizes.map(([size, label]) => (
        <Label key={size}>
          <Switch defaultChecked size={size} />
          {label}
        </Label>
      ))}
    </div>
  );
}

API reference

Component properties
PropTypeDefaultDescription
sizesm | md | lg | xlprovider / lgControl dimensions.
childrenReactNodeunsetRendered only for menu-item; the control supplies its own thumb.
checked / defaultCheckedbooleanunset / falseControlled state or initial state.
onCheckedChange(checked, eventDetails) => voidunsetCalled when the user changes the checked state.
disabledbooleanfalsePrevents interaction.
name / valuestringunsetNative form participation. An on switch submits value (on if value is unset).
uncheckedValuestringunsetValue submitted while the switch is off.

SwitchProps describes the size extension; SwitchPrimitive is the Base UI namespace. Other props, including required, readOnly, render and inputRef, follow Base UI Switch. Styled className is a string.

switchVariants({ size, className }) returns the classes of the switch track that menu rows draw, with lg size; switchThumbClassName and switchMenuTrackClassName export the matching thumb and track composition strings. The standalone control takes its look from the kit stylesheet, and so does the edge of every track: a menu row's track carries data-slot="switch-track" and gets the standalone control's 3:1 edge. They do not create switch behavior.

Read the installed source.

Usage notes

Space changes the focused control. Supply a visible associated Label or an accessible name. Use Checkbox Group for multiple related choices and Radio Group for exactly one choice. Switch has no indeterminate state.

The thumb rests at the inline start of the track and travels toward its end when the switch turns on, so in a right-to-left page it starts on the right and moves left, within the track. The same holds for the switch rows of menus.