Toggle
On/off switch with animation, glow effect, and ARIA switch role.
<arc-toggle>Overview
The Toggle component provides a binary on/off control that mirrors the behavior of a physical switch. Use it for a setting that takes immediate effect: turning a feature on or off, enabling a preference, activating a mode. Unlike a checkbox, which typically submits with a form, a toggle communicates instant state change to the user.
Internally, Toggle renders with role="switch" and manages aria-checked automatically, giving assistive technology a clear picture of the current state. The thumb slides between positions with a spring-timed CSS transition, and the active state lights up with a subtle glow drawn from the current theme's accent color. Both the track and the thumb inherit design tokens so the component stays consistent across light, dark, and high-contrast modes.
Toggle works equally well as an uncontrolled element (set checked once and let the component manage its own state) or as a fully controlled input driven by framework reactivity. It also participates in native form submission when given a name, emitting a boolean value alongside other form fields.
Guidelines
When to use
- Use a toggle for settings that take effect immediately (e.g. enable notifications)
- Provide a clear, concise label describing what the toggle controls
- Place toggles in a vertical list when presenting multiple related settings
- Use the `checked` attribute to set a sensible default for each option
- Pair with descriptive helper text when the label alone may be ambiguous
When not to use
- Do not use a toggle when the change requires an explicit "Save" action. Use a checkbox instead
- Avoid wrapping a toggle inside a clickable card or button. The double action confuses users
- Do not disable a toggle without explaining why the option is unavailable
- Avoid placing more than 8-10 toggles in a single group. Consider grouping into sections
- Do not use a toggle for mutually exclusive options. Use a radio group instead
Features
- Binary on/off state with animated thumb slide and glow transition
- Built-in `role="switch"` and automatic `aria-checked` management
- Keyboard accessible: Space and Enter keys toggle state
- Paired label rendered inline, with click-to-toggle support
- Disabled state with reduced opacity and blocked pointer events
- Participates in native `<form>` submission when `name` is set
- Theme-aware glow color derived from accent design tokens
- Works as controlled or uncontrolled input across all frameworks
Preview
Usage
Layout and styling work without JavaScript via the HTML/CSS versions. Interactive features like events and state management require the Web Component or a framework wrapper.
<arc-toggle label="Email notifications" checked></arc-toggle>
<arc-toggle label="Push notifications"></arc-toggle>
<arc-toggle label="Marketing emails"></arc-toggle>import { Toggle } from '@arclux/arc-ui-react';
export default function Example() {
return (
<>
<Toggle label="Email notifications" checked />
<Toggle label="Push notifications" />
<Toggle label="Marketing emails" />
</>
);
}<script setup>
import { Toggle } from '@arclux/arc-ui-vue';
</script>
<template>
<Toggle label="Email notifications" checked />
<Toggle label="Push notifications" />
<Toggle label="Marketing emails" />
</template><script>
import { Toggle } from '@arclux/arc-ui-svelte';
</script>
<Toggle label="Email notifications" checked />
<Toggle label="Push notifications" />
<Toggle label="Marketing emails" />import { Component } from '@angular/core';
import { Toggle } from '@arclux/arc-ui-angular';
@Component({
imports: [Toggle],
template: `
<arc-toggle label="Email notifications" checked></arc-toggle>
<arc-toggle label="Push notifications"></arc-toggle>
<arc-toggle label="Marketing emails"></arc-toggle>
`,
})
export class SettingsPanel {}import { Toggle } from '@arclux/arc-ui-solid';
export default function Example() {
return (
<>
<Toggle label="Email notifications" checked />
<Toggle label="Push notifications" />
<Toggle label="Marketing emails" />
</>
);
}import { Toggle } from '@arclux/arc-ui-preact';
export default function Example() {
return (
<>
<Toggle label="Email notifications" checked />
<Toggle label="Push notifications" />
<Toggle label="Marketing emails" />
</>
);
}<arc-toggle label="Email notifications" checked></arc-toggle>
<arc-toggle label="Push notifications"></arc-toggle>
<arc-toggle label="Marketing emails"></arc-toggle><!-- Auto-generated by @arclux/prism — do not edit manually -->
<!-- arc-toggle — self-contained, no external CSS needed -->
<div class="arc-toggle">
</div>API
disabledbooleanfalse- Prevents user interaction. The toggle appears at reduced opacity and ignores pointer and keyboard events.
labelstring''- Visible text rendered beside the toggle. Clicking the label also toggles the switch, matching native
<label>behavior. namestring''- Form field name submitted with the toggle value. When set, the component participates in native
<form>submission. checkedbooleanfalse- Whether the toggle is in the on position. When set, the thumb slides to the active side and the track displays the accent glow.
size'sm' | 'md' | 'lg''md'- Controls the toggle size.
formAssociatedbooleantruepropertiesobject{ // flag(), unlike `disabled`. The exclusion in props.js is specifically // about form-associated *platform* semantics: a `disabled` content // attribute that is merely present makes the element actually disabled // per the HTML spec, and formDisabledCallback assigns the property back, // so no converter can win. Neither of these is platform-mapped: // `required` is enforced by _computeValidity() below and `readonly` by // each component's own interaction handlers, so the stock converter buys // nothing here and costs the usual bug: `required="false"` read as true, // blocking submission of a form the author meant to leave optional. // Finding #48's shape, across all 26 form controls at once. required: flag(false), readonly: flag(false), }- Lit merges static properties up the prototype chain, so every consumer
gets these without declaring them.
requiredparticipates in constraint validation below;readonlyreflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state). autoValidatesbooleantrue- Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
formvalidityvalidationMessagerequiredbooleanfalsereadonlybooleanfalse
Methods
checkValidity()boolean- Whether the control currently satisfies its constraints, per the native
constraint-validation API. Fires
invalidon the element when it does not, and reports nothing to the user. reportValidity()boolean- As checkValidity(), but also shows the browser's validation message against the control when it fails.
Events
arc-changedetail:{ checked: boolean }- Fired when the toggle state changes
See Also
- CheckboxMulti-select form control with checked, indeterminate, and disabled states. For preferences, bulk selection, and consent forms where users toggle one or more independent options.
- Radio GroupSingle-select option group with arrow-key navigation and ARIA radiogroup semantics. Fits pricing tiers, settings panels, and any place where exactly one choice must be made from a visible set of options.