Skip to content

Switch

A two-state control that can be either on or off. Areia's Switch uses @data-slot/switch for accessible, form-ready behavior when rendered with Switch.

Source Code

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch label="Enable notifications" />
));

Import

import { Switch } from "areia";

Usage

Call Switch(...) for interactive behavior. It initializes @data-slot/switch, syncs ARIA/state attributes, creates form inputs, and emits change events.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch
    id="marketing-emails"
    label="Marketing emails"
    name="marketing-emails"
    value="enabled"
    uncheckedValue="disabled"
  />
));

Use Switch.Static(...) for static markup or when you want to initialize behavior yourself. For most application usage, call Switch(...).

Ilha bind:checked

Inside an Ilha island (including nested child islands), you can bind island state without onCheckedChange:

const Form = ilha
  .state("useBun", false)
  .render(({ state }) => (
    <Switch
      label="Use Bun"
      name="useBun"
      bind:checked={state.useBun}
    />
  ));

Requires ilha ^0.8.0 and a recent areia release. Controlled checked + onCheckedChange still works.

Examples

Off State

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => <Switch label="Dark mode" />);

On State

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch label="Dark mode" checked />
));

Disabled

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-3">
    <Switch label="Disabled off" disabled />
    <Switch label="Disabled on" checked disabled />
  </div>
));

Read Only

Use readOnly to prevent user changes while keeping the field enabled for form submission.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch label="Managed by policy" checked readOnly />
));

Variants

The Switch supports two variants: default for brand-colored toggles and neutral for monochrome toggles.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <div class="grid gap-3 sm:grid-cols-2">
    <Switch label="Default off" variant="default" />
    <Switch label="Default on" variant="default" checked />
    <Switch label="Neutral off" variant="neutral" />
    <Switch label="Neutral on" variant="neutral" checked />
  </div>
));

Neutral Variant

The neutral variant is useful for subtle, lower-emphasis settings.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch label="Compact setting" variant="neutral" />
));

Sizes

Three sizes are available: sm, base, and lg.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <div class="flex flex-col gap-3">
    <Switch label="Small" size="sm" />
    <Switch label="Base" size="base" />
    <Switch label="Large" size="lg" />
  </div>
));

Label First Layout

Use controlFirst: false to place the label before the switch.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch label="Enable beta features" controlFirst={false} />
));

With Tooltip and Optional Indicator

Use labelTooltip for contextual help. Set required: false to show the optional indicator.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch
    label="Usage analytics"
    labelTooltip="Helps improve the product by sending anonymous usage data."
    required={false}
  />
));

Custom ID

When a custom id is provided, clicking the label toggles the switch.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch id="custom-switch-id" label="Custom id switch" />
));

Without Visible Label

When a switch does not have visible label text, provide an accessible name with aria-label.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch aria-label="Enable setting" />
));

Switch Group

Group related switches with Switch.Group. It provides a shared legend, description, and error message for the group.

Notification settings

Choose how you want to receive account updates.

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch.Group
    legend="Notification settings"
    description="Choose how you want to receive account updates."
  >
    <Switch.Item
      label="Email notifications"
      name="email"
      value="enabled"
    />
    <Switch.Item
      label="SMS notifications"
      name="sms"
      value="enabled"
    />
    <Switch.Item
      label="Push notifications"
      name="push"
      value="enabled"
    />
  </Switch.Group>
));

Group Label First

Set controlFirst: false on the group to place labels before all switches in the group.

Privacy settings
import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch.Group legend="Privacy settings" controlFirst={false}>
    <Switch.Item
      label="Show profile publicly"
      name="public-profile"
    />
    <Switch.Item
      label="Allow search indexing"
      name="search-indexing"
    />
  </Switch.Group>
));

Visually Hidden Legend

Use Switch.Legend with class: "sr-only" to keep the legend accessible to screen readers while hiding it visually.

Notification settings

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch.Group>
    <Switch.Legend class="sr-only">
      Notification settings
    </Switch.Legend>
    <Switch.Item label="Email" name="email" />
    <Switch.Item label="SMS" name="sms" />
  </Switch.Group>
));

Custom Legend Styling

Use Switch.Legend directly when you need custom legend styling.

Notification settings

import ilha from "ilha";
import { Switch } from "areia";

export default ilha.render(() => (
  <Switch.Group>
    <Switch.Legend class="text-sm font-semibold uppercase tracking-wide text-areia-subtle">
      Notification settings
    </Switch.Legend>
    <Switch.Item
      label="Product updates"
      name="product-updates"
    />
    <Switch.Item
      label="Security alerts"
      name="security-alerts"
      checked
    />
  </Switch.Group>
));

Listening for Changes

Switch emits a bubbling switch:change event. You can also dispatch the inbound switch:set event supported by @data-slot/switch.

const switchRoot = document.querySelector(
  '[data-slot="switch"]',
);

switchRoot?.addEventListener("switch:change", (event) => {
  const { checked } = (event as CustomEvent).detail;
  console.log(checked);
});

switchRoot?.dispatchEvent(
  new CustomEvent("switch:set", { detail: { checked: true } }),
);

API Reference

Switch

Extends native span attributes for the switch control root.

PropTypeDefaultDescription
variant"default" | "neutral""default"Visual variant.
size"sm" | "base" | "lg""base"Switch size.
labelunknown-Label content. Optional for standalone visual switches.
labelTooltipstring-Tooltip text displayed next to the label.
requiredboolean-Native required state. false shows the optional indicator.
controlFirstbooleantruePlaces the switch before the label when true.
checkedboolean-Initial checked state for Switch.
defaultCheckedboolean-Initial checked state.
disabledboolean-Disables interaction and form submission.
readOnlyboolean-Prevents interaction while keeping the field enabled.
transitioningboolean-Sets aria-busy for pending state.
namestring-Form field name.
valuestring"on"Submitted value when checked.
uncheckedValuestring-Submitted value when unchecked.
onCheckedChange(checked: boolean) => void-Called by Switch when checked state changes.
classstring-Additional classes for the switch control.
classNamestring-Alias for class.

Switch

Switch is an Ilha island. It renders the switch and initializes @data-slot/switch with the provided options.

It emits:

EventDetailDescription
switch:change{ checked }Fired when checked state changes.

Switch.Group

Extends native fieldset attributes.

PropTypeDefaultDescription
legendunknown-Legend content for the group.
childrenunknown-Switch items and optional custom legend.
errorunknown-Error message for the group.
descriptionunknown-Helper text for the group.
disabledboolean-Disables all controls in the fieldset.
controlFirstbooleantrueControls label/control order for child items.
classstring-Additional classes.
classNamestring-Alias for class.

Subcomponents

ComponentDescription
Switch.ItemIndividual switch intended for use in a group.
Switch.LegendStyled legend for switch groups.
Switch.ControlBare switch control without field label wrapper.

Design Guidelines

When to Use Switch

  • Use switches for settings that take effect immediately.
  • Use checkboxes for form choices that are submitted together later.
  • Avoid switches for destructive or irreversible actions.

Accessibility

  • Provide label, aria-label, or aria-labelledby for every switch.
  • Group related switches with Switch.Group and a legend.
  • Use description to clarify when a setting takes effect.
  • Disabled switches should not be the only way to explain unavailable settings; include supporting text where needed.