Switch

An accessible on/off toggle (Base UI: role="switch" with a hidden real input, so it submits in a form and pairs with Field).

Colors

Sizes

Real use · notification settings

Using Switch

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Switch is styled but inert: its behavior comes from switch. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class switch, with 14 modifiers:

  • .switch
  • .switch-accent
  • .switch-error
  • .switch-info
  • .switch-lg
  • .switch-md
  • .switch-neutral
  • .switch-primary
  • .switch-secondary
  • .switch-sm
  • .switch-success
  • .switch-thumb
  • .switch-warning
  • .switch-xl
  • .switch-xs

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { Switch } from "@wizeworks/silicaui-react";

Props

PropTypeRequiredDescription
colorSilicaColornoAccent for the checked track.
sizeSilicaSizenoTrack height (width follows at 1.75×).

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { useState } from "react";
import { Switch } from "@wizeworks/silicaui-react";
import { Section, Row } from "../lib/Section";
import { SIZES } from "../lib/data";

const SETTINGS = [
    { key: "push", label: "Push notifications", defaultOn: true },
    { key: "email", label: "Email digest", defaultOn: true },
    { key: "sms", label: "SMS alerts", defaultOn: false },
];

export function SwitchDemo() {
    const [on, setOn] = useState<Record<string, boolean>>({
        push: true,
        email: true,
        sms: false,
    });

    return (
        <>
            <Section title="Colors">
                <Row>
                    <Switch defaultChecked />
                    <Switch color="primary" defaultChecked />
                    <Switch color="success" defaultChecked />
                    <Switch color="warning" defaultChecked />
                    <Switch color="error" defaultChecked />
                    <Switch color="brand" defaultChecked />
                    <Switch disabled />
                </Row>
            </Section>

            <Section title="Sizes">
                <Row>
                    {SIZES.filter((s) => s !== "xl").map((size) => (
                        <Switch key={size} color="primary" size={size} defaultChecked />
                    ))}
                </Row>
            </Section>

            <Section title="Real use · notification settings">
                <div className="flex max-w-sm flex-col gap-3 rounded-box border border-base-300 bg-base-100 p-4">
                    {SETTINGS.map((s) => (
                        <label key={s.key} className="flex items-center justify-between gap-4 text-sm">
                            {s.label}
                            <Switch
                                color="primary"
                                checked={on[s.key]}
                                onCheckedChange={(v) => setOn((p) => ({ ...p, [s.key]: v }))}
                            />
                        </label>
                    ))}
                </div>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

switch — a role=switch element the CSS keys off [data-checked] for (Base UI's synthetic attribute, ported verbatim — a bare <input type=checkbox> would NOT match .switch's selectors). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("Switch", "switch", { /* props */ });
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "switch switch-primary" rather than passing a colour as a prop.

Takes children
no
Hydrated by
switch

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Switch, on every path, is available through the Silica MCP server.