Skip to content

HySwitch

A form-associated switch component that toggles between on and off states. Provides comprehensive form integration via the ElementInternals API, accessibility features, and customizable styling.

Key Behavioral Model

This switch implements a clear separation between user interactions and programmatic control:

User Interactions (Mouse clicks, Space key)

  • Binary states: Toggle between offon
  • Standard behavior: Follows native switch/toggle conventions
  • Predictable UX: Users get consistent toggle behavior

Programmatic Control (JavaScript methods)

  • Method-controlled: Use setState(), toggle(), turnOn(), turnOff()
  • Event tracking: All changes include reason field ('user' | 'programmatic')

Form Integration

This component implements the Form-Associated Custom Elements API, allowing it to participate in form submission just like native checkboxes. The switch's value will be included in FormData when in the "on" state and the form is submitted.

Usage Guidelines

Switches are ideal for settings that take effect immediately and represent binary on/off states. Use switches for enabling/disabling features, toggling preferences, or controlling visibility. For selections that require a form submission, consider using checkboxes instead.

Sizes

  • small: Compact switch for dense layouts or inline controls
  • medium (default): Standard switch size for most use cases
  • large: Prominent switch for emphasis or improved touch targets

Variants

  • default: Standard switch appearance
  • error: Red-themed switch indicating error state or required field validation

States

  • off: Inactive state (default)
  • on: Active/enabled state
  • disabled: Non-interactive state (can be combined with off/on)

Keyboard Navigation

  • Space key: Toggles between offon
  • Tab: Moves focus to/from the switch
  • Enter: No effect (standard switch behavior - doesn't change state)

Examples

Basic toggle

html
<hy-switch name="notifications" value="enabled" label="Enable notifications"> </hy-switch>

Form submission

html
<form>
  <hy-switch name="dark-mode" value="enabled" label="Dark mode"> </hy-switch>
  <button type="submit">Save</button>
</form>

With top label and help text

html
<hy-switch
  name="newsletter"
  value="subscribed"
  top-label="Newsletter Preferences"
  label="Subscribe to weekly newsletter"
  help-text="Get the latest updates delivered to your inbox"
>
</hy-switch>

Required field with error variant

html
<form>
  <hy-switch
    name="terms"
    value="accepted"
    label="Accept terms and conditions"
    help-text="You must accept to continue"
    required
    variant="error"
  >
  </hy-switch>
  <button type="submit">Submit</button>
</form>

Different sizes

html
<hy-switch size="small" label="Small switch"></hy-switch>
<hy-switch size="medium" label="Medium switch"></hy-switch>
<hy-switch size="large" label="Large switch"></hy-switch>

Disabled states

html
<hy-switch label="Disabled off" disabled></hy-switch>
<hy-switch label="Disabled on" state="on" disabled></hy-switch>

Programmatic control

javascript
const switchElement = document.querySelector('hy-switch');

// Turn on
switchElement.turnOn();

// Turn off
switchElement.turnOff();

// Toggle
switchElement.toggle();

// Check state
console.log(switchElement.checked); // true/false
console.log(switchElement.state); // 'on'/'off'

// Form validation
if (switchElement.checkValidity()) {
  console.log('Valid');
} else {
  switchElement.reportValidity();
}

Event handling

css
switchElement.addEventListener('change', (e) => {
console.log({
state: e.detail.state,        // 'on' or 'off'
checked: e.detail.checked,    // true or false
value: e.detail.value,        // switch's value attribute
reason: e.detail.reason       // 'user' or 'programmatic'
});

// Save setting immediately
if (e.detail.reason === 'user') {
savePreference(e.detail.checked);
}
});

Using slots for dynamic content

html
<hy-switch name="privacy" value="enabled">
  <span slot="top-label">
    Privacy Settings
    <hy-icon name="shield"></hy-icon>
  </span>
  <span slot="help-text"> Learn more about our <a href="/privacy">privacy policy</a> </span>
</hy-switch>

Complete settings interface

html
<form>
  <fieldset>
    <legend>Notification Preferences</legend>

    <hy-switch
      name="email-notifications"
      value="enabled"
      label="Email notifications"
      help-text="Receive updates via email"
      state="on"
    >
    </hy-switch>

    <hy-switch
      name="push-notifications"
      value="enabled"
      label="Push notifications"
      help-text="Receive push notifications in browser"
      state="on"
    >
    </hy-switch>

    <hy-switch
      name="sms-notifications"
      value="enabled"
      label="SMS notifications"
      help-text="Receive text message alerts"
      disabled
    >
    </hy-switch>
  </fieldset>

  <button type="submit">Save Preferences</button>
</form>

Programmatic Methods

javascript
const switchEl = document.querySelector('hy-switch');

// State control
switchEl.turnOn();
switchEl.turnOff();
switchEl.toggle();

// Form validation
switchEl.checkValidity();
switchEl.reportValidity();

// Focus management
switchEl.focus();
switchEl.blur();

// Access form
console.log(switchEl.form);
console.log(switchEl.validity);
console.log(switchEl.validationMessage);

Events

  • change - Fired when state changes, includes state, checked, value, and reason
  • change - Standard form change event
  • input - Standard form input event

Slots

  • top-label - Content above the switch
  • help-text - Content below the switch
  • check-icon - Icon rendered inside the thumb when state is on. Defaults to a check icon.
  • uncheck-icon - Icon rendered inside the thumb when state is off. Empty by default; useful for binary-meaning switches (e.g. sun/moon for a theme toggle).

Methods

willUpdate()

Generates unique IDs before the first render to prevent update-after-update warnings. IDs are generated client-side only to prevent SSR/client hydration mismatches.

checkValidity()

Checks if the switch is valid according to form validation rules. Returns true if valid, false otherwise.

javascript
const switchEl = document.querySelector('hy-switch');
if (!switchEl.checkValidity()) {
  console.log('Switch is invalid');
}

reportValidity()

Checks validity and shows browser validation UI if invalid. Returns true if valid, false otherwise.

javascript
const switchEl = document.querySelector('hy-switch');
if (!switchEl.reportValidity()) {
  console.log('Switch is invalid and message shown');
}

toggle()

Toggles the switch between 'on' and 'off' states programmatically. Does nothing if the switch is disabled.

javascript
const switchEl = document.querySelector('hy-switch');
switchEl.toggle(); // off -> on or on -> off

turnOn()

Turns the switch to 'on' state programmatically. Does nothing if the switch is disabled.

javascript
const switchEl = document.querySelector('hy-switch');
switchEl.turnOn();

turnOff()

Turns the switch to 'off' state programmatically. Does nothing if the switch is disabled.

javascript
const switchEl = document.querySelector('hy-switch');
switchEl.turnOff();

focus()

Sets focus on the switch input.

javascript
const switchEl = document.querySelector('hy-switch');
switchEl.focus();

blur()

Removes focus from the switch input.

javascript
const switchEl = document.querySelector('hy-switch');
switchEl.blur();

Built with Lit. Documented with VitePress.