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.
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.
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.
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.
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.
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.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "neutral" | "default" | Visual variant. |
size | "sm" | "base" | "lg" | "base" | Switch size. |
label | unknown | - | Label content. Optional for standalone visual switches. |
labelTooltip | string | - | Tooltip text displayed next to the label. |
required | boolean | - | Native required state. false shows the optional indicator. |
controlFirst | boolean | true | Places the switch before the label when true. |
checked | boolean | - | Initial checked state for Switch. |
defaultChecked | boolean | - | Initial checked state. |
disabled | boolean | - | Disables interaction and form submission. |
readOnly | boolean | - | Prevents interaction while keeping the field enabled. |
transitioning | boolean | - | Sets aria-busy for pending state. |
name | string | - | Form field name. |
value | string | "on" | Submitted value when checked. |
uncheckedValue | string | - | Submitted value when unchecked. |
onCheckedChange | (checked: boolean) => void | - | Called by Switch when checked state changes. |
class | string | - | Additional classes for the switch control. |
className | string | - | Alias for class. |
Switch
Switch is an Ilha island. It renders the switch and initializes @data-slot/switch with the provided options.
It emits:
| Event | Detail | Description |
|---|---|---|
switch:change | { checked } | Fired when checked state changes. |
Switch.Group
Extends native fieldset attributes.
| Prop | Type | Default | Description |
|---|---|---|---|
legend | unknown | - | Legend content for the group. |
children | unknown | - | Switch items and optional custom legend. |
error | unknown | - | Error message for the group. |
description | unknown | - | Helper text for the group. |
disabled | boolean | - | Disables all controls in the fieldset. |
controlFirst | boolean | true | Controls label/control order for child items. |
class | string | - | Additional classes. |
className | string | - | Alias for class. |
Subcomponents
| Component | Description |
|---|---|
Switch.Item | Individual switch intended for use in a group. |
Switch.Legend | Styled legend for switch groups. |
Switch.Control | Bare 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, oraria-labelledbyfor every switch. - Group related switches with
Switch.Groupand a legend. - Use
descriptionto clarify when a setting takes effect. - Disabled switches should not be the only way to explain unavailable settings; include supporting text where needed.