Skip to content
Praesepe UI

forms

Switch

Accessible toggle switch built on a native checkbox with role="switch", sm/md sizes, label, description, and attribute forwarding.

Copied!

Examples

Basic switch

Label and description with attribute forwarding.

Copied!

Email me when a deploy finishes.

<x-ui.switch
    name="notifications"
    value="1"
    label="Product notifications"
    description="Email me when a deploy finishes."
    checked
    class="max-w-md"
/>
<div class="w-full max-w-md">
    <div class="flex items-start gap-3">
        <div class="relative inline-flex shrink-0">
            <input
                id="notifications-basic"
                type="checkbox"
                role="switch"
                name="notifications"
                value="1"
                checked
                aria-describedby="notifications-basic-description"
                class="peer absolute inset-0 z-10 h-6 w-11 cursor-pointer opacity-0"
            >
            <span class="pointer-events-none inline-flex h-6 w-11 items-center rounded-pill bg-border-strong p-0.5 transition-colors peer-checked:bg-brand peer-checked:[&_.thumb]:translate-x-5" aria-hidden="true">
                <span class="thumb block size-5 rounded-full bg-surface-raised shadow-sm transition-transform"></span>
            </span>
        </div>
        <div>
            <label for="notifications-basic" class="block text-sm font-medium text-fg">Product notifications</label>
            <p id="notifications-basic-description" class="mt-0.5 text-sm text-fg-muted">Email me when a deploy finishes.</p>
        </div>
    </div>
</div>

Sizes

sm and md track sizes.

Copied!
<div class="flex flex-col gap-4">
    <x-ui.switch size="sm" name="size_sm" aria-label="Small switch" label="Small" />
    <x-ui.switch size="md" name="size_md" aria-label="Medium switch" label="Medium" checked />
</div>
<div class="flex flex-col gap-4">
    <div class="flex items-center gap-3">
        <div class="relative inline-flex">
            <input type="checkbox" role="switch" class="peer absolute inset-0 z-10 h-5 w-9 cursor-pointer opacity-0" aria-label="Small switch">
            <span class="pointer-events-none inline-flex h-5 w-9 items-center rounded-pill bg-border-strong p-0.5 peer-checked:bg-brand peer-checked:[&_.thumb]:translate-x-4" aria-hidden="true">
                <span class="thumb block size-4 rounded-full bg-surface-raised shadow-sm transition-transform"></span>
            </span>
        </div>
        <span class="text-sm text-fg">Small</span>
    </div>
    <div class="flex items-center gap-3">
        <div class="relative inline-flex">
            <input type="checkbox" role="switch" checked class="peer absolute inset-0 z-10 h-6 w-11 cursor-pointer opacity-0" aria-label="Medium switch">
            <span class="pointer-events-none inline-flex h-6 w-11 items-center rounded-pill bg-border-strong p-0.5 peer-checked:bg-brand peer-checked:[&_.thumb]:translate-x-5" aria-hidden="true">
                <span class="thumb block size-5 rounded-full bg-surface-raised shadow-sm transition-transform"></span>
            </span>
        </div>
        <span class="text-sm text-fg">Medium</span>
    </div>
</div>

Disabled

Non-interactive disabled state.

Copied!

Only owners can change this setting.

<x-ui.switch
    name="maintenance"
    label="Maintenance mode"
    description="Only owners can change this setting."
    disabled
    class="max-w-md"
/>
<div class="w-full max-w-md">
    <div class="flex items-start gap-3">
        <div class="relative inline-flex shrink-0">
            <input
                id="maintenance-disabled"
                type="checkbox"
                role="switch"
                name="maintenance"
                disabled
                class="peer absolute inset-0 z-10 h-6 w-11 cursor-not-allowed opacity-0"
            >
            <span class="pointer-events-none inline-flex h-6 w-11 items-center rounded-pill bg-border-strong p-0.5 opacity-50" aria-hidden="true">
                <span class="thumb block size-5 rounded-full bg-surface-raised shadow-sm"></span>
            </span>
        </div>
        <div>
            <label for="maintenance-disabled" class="block text-sm font-medium text-fg">Maintenance mode</label>
            <p class="mt-0.5 text-sm text-fg-muted">Only owners can change this setting.</p>
        </div>
    </div>
</div>

Props API

Component props
Prop Type Default Description
size sm|md md Track and thumb size.
label string|null null Visible label linked via for/id.
description string|null null Supporting text referenced by aria-describedby.

Accessibility notes

Architected with WCAG 2.2 AA patterns in mind. These notes document the exact keyboard and ARIA behavior for this component.

  • Uses input type="checkbox" with role="switch". Browsers expose checked state as the switch value for assistive tech.
  • Label for and input id are linked. Description contributes to aria-describedby when present.
  • Focus-visible outline uses the shared --ui-ring token on the painted track via peer-focus-visible.
  • Pass-through attributes (name, value, checked, disabled, required, x-model, wire:model) land on the checkbox so standard form posts and Livewire bindings work.
  • Keyboard: Tab focuses the switch. Space toggles on and off.

Built by Praesepe

Architecture & custom software partner

Praesepe uses these exact UI primitives to ship SME dashboards, inventory systems, invoicing desks, and internal tools faster, without rebuilding a design system for every client.

  • Same Blade + Tailwind 4 + Alpine 3 stack you see in this docs site
  • Opinionated for Indonesian SME ops: invoices, stock, roles, approvals
  • Architected with WCAG 2.2 AA patterns in mind for keyboard and ARIA

Talk to the studio

WhatsApp: TODO Email the studio Visit Praesepe