md-switch spec card
Identity · when to use / when NOT · decision cues · behavioural contract · do/don't · anti-patterns · full API. Paste into your agent when you're implementing with this component.
An immediate on/off setting. A track-and-handle toggle with optional state
icons, form participation via ElementInternals, and a cancelable
before-change event for controlled usage.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected></md-switch>
Dark mode
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch icons></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch selected></MdSwitch>
Dark mode
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch icons></MdSwitch>
Wi-Fi
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch selected icons></MdSwitch>
Bluetooth
</label>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected></md-switch>
Dark mode
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch icons></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label><script setup>
import '@awc-ui/core/define';
</script>
<template>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected></md-switch>
Dark mode
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch icons></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>
</template><script>
import '@awc-ui/core/define';
</script>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected></md-switch>
Dark mode
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch icons></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>
Already installed? See the
Installation guide for one-time package setup
(core + tokens, fonts). Each tab below shows two patterns for using
md-switch in your project: Option A registers every AWC UI
component at once (simplest), Option B imports only this component for
tree-shake-friendly bundles.
<!-- ─── Option A: global registration (all components) ─── -->
<script type="module">
import '@awc-ui/core/define';
</script>
<!-- ─── Option B: single import (tree-shake only md-switch) ─── -->
<script type="module">
import '@awc-ui/core/components/md-switch';
</script>
<md-switch></md-switch>// ─── Option A: typed React wrapper (registers all components) ───
// Importing from '@awc-ui/react' calls defineCustomElements() as a
// side effect, so every md-* element becomes available in the browser.
import { MdSwitch } from '@awc-ui/react';
export function Example() {
return <MdSwitch></MdSwitch>;
}
// ─── Option B: single import (tree-shake to only md-switch) ───
// Skip the wrapper and use the raw custom element. Smallest bundle,
// but you lose typed props/events on JSX.
import '@awc-ui/core/components/md-switch';
export function ExampleTreeShaken() {
return <md-switch></md-switch>;
}// ─── Option A: schema module (any md-* element accepted) ───
// Pair with `defineCustomElements(window)` in main.ts.
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `<md-switch></md-switch>`,
})
export class ExampleComponent {}
// ─── Option B: typed directive (tree-shake friendly) ───
// Pair with `import '@awc-ui/core/components/md-switch'` in main.ts.
import { Component } from '@angular/core';
import { MdSwitch } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [MdSwitch],
template: `<md-switch></md-switch>`,
})
export class ExampleTreeShakenComponent {}<!-- ─── Option A: typed Vue wrapper (registers all components) ─── -->
<script setup lang="ts">
import { MdSwitch } from '@awc-ui/vue';
</script>
<template>
<MdSwitch></MdSwitch>
</template>
<!-- ─── Option B: single import (tree-shake to only md-switch) ─── -->
<script setup lang="ts">
import '@awc-ui/core/components/md-switch';
</script>
<template>
<md-switch></md-switch>
</template><!-- ─── Option A: global registration (done once in main entry) ─── -->
<!-- main.ts: -->
<!-- import { defineCustomElements } from '@awc-ui/svelte'; -->
<!-- defineCustomElements(window); -->
<md-switch></md-switch>
<!-- ─── Option B: single import (tree-shake to only md-switch) ─── -->
<script lang="ts">
import '@awc-ui/core/components/md-switch';
</script>
<md-switch></md-switch>| Situation | Use instead |
|---|---|
| Selecting one or more options from a list | md-checkbox |
| Selecting exactly one from a list | md-radio |
| Choosing between two opposing options (A vs B) | md-button-group, connected |
| The change requires an explicit save step | md-checkbox |
| Triggering an action | md-button |
| Filtering | md-chip |
| A value in a range | md-slider |
Put the label outside the control — M3 is explicit that text inside a switch would be inaccessibly small. Describe what on does, and keep it short.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 16px;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch disabled></md-switch>
Airplane mode
</label>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch></MdSwitch>
Wi-Fi
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch selected icons></MdSwitch>
Bluetooth
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch disabled></MdSwitch>
Airplane mode
</label>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; flex-direction: column; gap: 16px;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch disabled></md-switch>
Airplane mode
</label>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; flex-direction: column; gap: 16px;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch disabled></md-switch>
Airplane mode
</label>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; flex-direction: column; gap: 16px;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch></md-switch>
Wi-Fi
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch selected icons></md-switch>
Bluetooth
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch disabled></md-switch>
Airplane mode
</label>
</div>icons puts a glyph on both states (defaults check / close).
show-only-selected-icon shows one only when on. Without either prop the handle
is a plain disc — and slotted icons are ignored.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Without icons</span>
<md-switch aria-label="Without icons, off"></md-switch>
<md-switch selected aria-label="Without icons, on"></md-switch>
<span>Icon on selected</span>
<md-switch show-only-selected-icon aria-label="Icon on selected, off"></md-switch>
<md-switch selected show-only-selected-icon aria-label="Icon on selected, on"></md-switch>
<span>Icons on both</span>
<md-switch icons aria-label="Icons on both, off"></md-switch>
<md-switch selected icons aria-label="Icons on both, on"></md-switch>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto auto auto', gap: '16px 20px', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<span>Without icons</span>
<MdSwitch aria-label="Without icons, off"></MdSwitch>
<MdSwitch selected aria-label="Without icons, on"></MdSwitch>
<span>Icon on selected</span>
<MdSwitch showOnlySelectedIcon aria-label="Icon on selected, off"></MdSwitch>
<MdSwitch selected showOnlySelectedIcon aria-label="Icon on selected, on"></MdSwitch>
<span>Icons on both</span>
<MdSwitch icons aria-label="Icons on both, off"></MdSwitch>
<MdSwitch selected icons aria-label="Icons on both, on"></MdSwitch>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Without icons</span>
<md-switch aria-label="Without icons, off"></md-switch>
<md-switch selected aria-label="Without icons, on"></md-switch>
<span>Icon on selected</span>
<md-switch show-only-selected-icon aria-label="Icon on selected, off"></md-switch>
<md-switch selected show-only-selected-icon aria-label="Icon on selected, on"></md-switch>
<span>Icons on both</span>
<md-switch icons aria-label="Icons on both, off"></md-switch>
<md-switch selected icons aria-label="Icons on both, on"></md-switch>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Without icons</span>
<md-switch aria-label="Without icons, off"></md-switch>
<md-switch selected aria-label="Without icons, on"></md-switch>
<span>Icon on selected</span>
<md-switch show-only-selected-icon aria-label="Icon on selected, off"></md-switch>
<md-switch selected show-only-selected-icon aria-label="Icon on selected, on"></md-switch>
<span>Icons on both</span>
<md-switch icons aria-label="Icons on both, off"></md-switch>
<md-switch selected icons aria-label="Icons on both, on"></md-switch>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Without icons</span>
<md-switch aria-label="Without icons, off"></md-switch>
<md-switch selected aria-label="Without icons, on"></md-switch>
<span>Icon on selected</span>
<md-switch show-only-selected-icon aria-label="Icon on selected, off"></md-switch>
<md-switch selected show-only-selected-icon aria-label="Icon on selected, on"></md-switch>
<span>Icons on both</span>
<md-switch icons aria-label="Icons on both, off"></md-switch>
<md-switch selected icons aria-label="Icons on both, on"></md-switch>
</div>selected-icon / unselected-icon take any Material Symbols name, and the
matching slots take arbitrary markup. The selected glyph is gated by icons
or show-only-selected-icon; the unselected glyph is gated by icons
alone — a slotted glyph alone will not appear.
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Default (check / close)</span>
<md-switch icons aria-label="Default icons, off"></md-switch>
<md-switch selected icons aria-label="Default icons, on"></md-switch>
<span>bolt / power_off</span>
<md-switch icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, off"></md-switch>
<md-switch selected icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, on"></md-switch>
<span>dark_mode / light_mode</span>
<md-switch icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, off"></md-switch>
<md-switch selected icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, on"></md-switch>
<span>Slotted SVG</span>
<md-switch icons aria-label="Slotted SVG icons, off">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
<md-switch selected icons aria-label="Slotted SVG icons, on">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
</div>// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto auto auto', gap: '16px 20px', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<span>Default (check / close)</span>
<MdSwitch icons aria-label="Default icons, off"></MdSwitch>
<MdSwitch selected icons aria-label="Default icons, on"></MdSwitch>
<span>bolt / power_off</span>
<MdSwitch icons selectedIcon="bolt" unselectedIcon="power_off" aria-label="Glyph overrides, off"></MdSwitch>
<MdSwitch selected icons selectedIcon="bolt" unselectedIcon="power_off" aria-label="Glyph overrides, on"></MdSwitch>
<span>dark_mode / light_mode</span>
<MdSwitch icons selectedIcon="dark_mode" unselectedIcon="light_mode" aria-label="Theme icons, off"></MdSwitch>
<MdSwitch selected icons selectedIcon="dark_mode" unselectedIcon="light_mode" aria-label="Theme icons, on"></MdSwitch>
<span>Slotted SVG</span>
<MdSwitch icons aria-label="Slotted SVG icons, off">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</MdSwitch>
<MdSwitch selected icons aria-label="Slotted SVG icons, on">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</MdSwitch>
</div>
</>
);
}// Icons need the Material Symbols stylesheet in index.html — see Installation.
// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Default (check / close)</span>
<md-switch icons aria-label="Default icons, off"></md-switch>
<md-switch selected icons aria-label="Default icons, on"></md-switch>
<span>bolt / power_off</span>
<md-switch icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, off"></md-switch>
<md-switch selected icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, on"></md-switch>
<span>dark_mode / light_mode</span>
<md-switch icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, off"></md-switch>
<md-switch selected icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, on"></md-switch>
<span>Slotted SVG</span>
<md-switch icons aria-label="Slotted SVG icons, off">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
<md-switch selected icons aria-label="Slotted SVG icons, on">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
</div><script setup>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Default (check / close)</span>
<md-switch icons aria-label="Default icons, off"></md-switch>
<md-switch selected icons aria-label="Default icons, on"></md-switch>
<span>bolt / power_off</span>
<md-switch icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, off"></md-switch>
<md-switch selected icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, on"></md-switch>
<span>dark_mode / light_mode</span>
<md-switch icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, off"></md-switch>
<md-switch selected icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, on"></md-switch>
<span>Slotted SVG</span>
<md-switch icons aria-label="Slotted SVG icons, off">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
<md-switch selected icons aria-label="Slotted SVG icons, on">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
</div>
</template><script>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Default (check / close)</span>
<md-switch icons aria-label="Default icons, off"></md-switch>
<md-switch selected icons aria-label="Default icons, on"></md-switch>
<span>bolt / power_off</span>
<md-switch icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, off"></md-switch>
<md-switch selected icons selected-icon="bolt" unselected-icon="power_off" aria-label="Glyph overrides, on"></md-switch>
<span>dark_mode / light_mode</span>
<md-switch icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, off"></md-switch>
<md-switch selected icons selected-icon="dark_mode" unselected-icon="light_mode" aria-label="Theme icons, on"></md-switch>
<span>Slotted SVG</span>
<md-switch icons aria-label="Slotted SVG icons, off">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
<md-switch selected icons aria-label="Slotted SVG icons, on">
<svg slot="selected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.2 4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4z"/></svg>
<svg slot="unselected-icon" viewBox="0 0 24 24" fill="currentColor"><path d="M19 6.4 17.6 5 12 10.6 6.4 5 5 6.4 10.6 12 5 17.6 6.4 19 12 13.4 17.6 19 19 17.6 13.4 12z"/></svg>
</md-switch>
</div>M3 warns against ambiguous, non-binary glyphs. A moon on the handle of a dark-mode switch reads as decoration; put the moon in the label and keep check / X on the handle.
| State | Focusable | Use when |
|---|---|---|
| Enabled | Yes | Normal |
disabled | No (tabindex="-1") | Unavailable and undiscoverable |
soft-disabled | Yes (tabindex="0") | Contextually unavailable but worth discovering |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Enabled</span>
<md-switch aria-label="Enabled, off"></md-switch>
<md-switch selected aria-label="Enabled, on"></md-switch>
<span>Disabled</span>
<md-switch disabled aria-label="Disabled, off"></md-switch>
<md-switch selected disabled aria-label="Disabled, on"></md-switch>
<span>Soft-disabled</span>
<md-switch soft-disabled aria-label="Soft-disabled, off"></md-switch>
<md-switch selected soft-disabled aria-label="Soft-disabled, on"></md-switch>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto auto auto', gap: '16px 20px', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<span>Enabled</span>
<MdSwitch aria-label="Enabled, off"></MdSwitch>
<MdSwitch selected aria-label="Enabled, on"></MdSwitch>
<span>Disabled</span>
<MdSwitch disabled aria-label="Disabled, off"></MdSwitch>
<MdSwitch selected disabled aria-label="Disabled, on"></MdSwitch>
<span>Soft-disabled</span>
<MdSwitch softDisabled aria-label="Soft-disabled, off"></MdSwitch>
<MdSwitch selected softDisabled aria-label="Soft-disabled, on"></MdSwitch>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Enabled</span>
<md-switch aria-label="Enabled, off"></md-switch>
<md-switch selected aria-label="Enabled, on"></md-switch>
<span>Disabled</span>
<md-switch disabled aria-label="Disabled, off"></md-switch>
<md-switch selected disabled aria-label="Disabled, on"></md-switch>
<span>Soft-disabled</span>
<md-switch soft-disabled aria-label="Soft-disabled, off"></md-switch>
<md-switch selected soft-disabled aria-label="Soft-disabled, on"></md-switch>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Enabled</span>
<md-switch aria-label="Enabled, off"></md-switch>
<md-switch selected aria-label="Enabled, on"></md-switch>
<span>Disabled</span>
<md-switch disabled aria-label="Disabled, off"></md-switch>
<md-switch selected disabled aria-label="Disabled, on"></md-switch>
<span>Soft-disabled</span>
<md-switch soft-disabled aria-label="Soft-disabled, off"></md-switch>
<md-switch selected soft-disabled aria-label="Soft-disabled, on"></md-switch>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: grid; grid-template-columns: auto auto auto; gap: 16px 20px; align-items: center; color: var(--md-sys-color-on-surface);">
<span>Enabled</span>
<md-switch aria-label="Enabled, off"></md-switch>
<md-switch selected aria-label="Enabled, on"></md-switch>
<span>Disabled</span>
<md-switch disabled aria-label="Disabled, off"></md-switch>
<md-switch selected disabled aria-label="Disabled, on"></md-switch>
<span>Soft-disabled</span>
<md-switch soft-disabled aria-label="Soft-disabled, off"></md-switch>
<md-switch selected soft-disabled aria-label="Soft-disabled, on"></md-switch>
</div>md-switch is form-associated: when selected it submits value (default
"on") under name, and a form reset restores its initial state. required
genuinely blocks submission until the switch is on — customise the message with
value-missing-label.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<form style="display: flex; flex-direction: column; gap: 16px; align-items: flex-start;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="terms" required value-missing-label="Please turn this on if you want to proceed."></md-switch>
Accept the terms (required)
</label>
<div style="display: flex; gap: 12px;">
<md-button variant="filled" type="submit">Save</md-button>
<md-button variant="text" type="reset">Reset</md-button>
</div>
</form>import { MdButton, MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<form style={{ display: 'flex', flexDirection: 'column', gap: '16px', alignItems: 'flex-start' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch name="notifications" value="on" selected></MdSwitch>
Email notifications
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch name="terms" required valueMissingLabel="Please turn this on if you want to proceed."></MdSwitch>
Accept the terms (required)
</label>
<div style={{ display: 'flex', gap: '12px' }}>
<MdButton variant="filled" type="submit">Save</MdButton>
<MdButton variant="text" type="reset">Reset</MdButton>
</div>
</form>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<form style="display: flex; flex-direction: column; gap: 16px; align-items: flex-start;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="terms" required value-missing-label="Please turn this on if you want to proceed."></md-switch>
Accept the terms (required)
</label>
<div style="display: flex; gap: 12px;">
<md-button variant="filled" type="submit">Save</md-button>
<md-button variant="text" type="reset">Reset</md-button>
</div>
</form><script setup>
import '@awc-ui/core/define';
</script>
<template>
<form style="display: flex; flex-direction: column; gap: 16px; align-items: flex-start;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="terms" required value-missing-label="Please turn this on if you want to proceed."></md-switch>
Accept the terms (required)
</label>
<div style="display: flex; gap: 12px;">
<md-button variant="filled" type="submit">Save</md-button>
<md-button variant="text" type="reset">Reset</md-button>
</div>
</form>
</template><script>
import '@awc-ui/core/define';
</script>
<form style="display: flex; flex-direction: column; gap: 16px; align-items: flex-start;">
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label style="display: flex; align-items: center; gap: 12px; color: var(--md-sys-color-on-surface); cursor: pointer;">
<md-switch name="terms" required value-missing-label="Please turn this on if you want to proceed."></md-switch>
Accept the terms (required)
</label>
<div style="display: flex; gap: 12px;">
<md-button variant="filled" type="submit">Save</md-button>
<md-button variant="text" type="reset">Reset</md-button>
</div>
</form>Reading the submitted values is ordinary form work — the switch is in FormData
under its name, with no wrapper API of its own:
<form id="settings">
<label>
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label>
<md-switch name="terms" required value-missing-label="Please turn this on if you want to proceed."></md-switch>
Accept the terms
</label>
<md-button variant="filled" type="submit">Save</md-button>
</form>
<script type="module">
document.getElementById('settings').addEventListener('submit', (e) => {
e.preventDefault();
const data = new FormData(e.currentTarget);
// "on" when selected, null when not
console.log(data.get('notifications'), data.get('terms'));
});
</script>import { MdSwitch, MdButton } from '@awc-ui/react';
export function SettingsForm() {
function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const data = new FormData(e.currentTarget);
// "on" when selected, null when not
console.log(data.get('notifications'), data.get('terms'));
}
return (
<form onSubmit={onSubmit}>
<label>
<MdSwitch name="notifications" value="on" selected />
Email notifications
</label>
<label>
<MdSwitch
name="terms"
required
valueMissingLabel="Please turn this on if you want to proceed."
/>
Accept the terms
</label>
<MdButton variant="filled" type="submit">Save</MdButton>
</form>
);
}import { Component } from '@angular/core';
@Component({
selector: 'app-settings-form',
template: `
<form (submit)="onSubmit($event)">
<label>
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label>
<md-switch
name="terms"
required
value-missing-label="Please turn this on if you want to proceed."
></md-switch>
Accept the terms
</label>
<md-button variant="filled" type="submit">Save</md-button>
</form>
`,
})
export class SettingsFormComponent {
onSubmit(e: Event) {
e.preventDefault();
const data = new FormData(e.target as HTMLFormElement);
// "on" when selected, null when not
console.log(data.get('notifications'), data.get('terms'));
}
}<script setup lang="ts">
function onSubmit(e: Event) {
e.preventDefault();
const data = new FormData(e.target as HTMLFormElement);
// "on" when selected, null when not
console.log(data.get('notifications'), data.get('terms'));
}
</script>
<template>
<form @submit="onSubmit">
<label>
<md-switch name="notifications" value="on" selected />
Email notifications
</label>
<label>
<md-switch
name="terms"
required
value-missing-label="Please turn this on if you want to proceed."
/>
Accept the terms
</label>
<md-button variant="filled" type="submit">Save</md-button>
</form>
</template><script lang="ts">
function onSubmit(e: Event) {
e.preventDefault();
const data = new FormData(e.target as HTMLFormElement);
// "on" when selected, null when not
console.log(data.get('notifications'), data.get('terms'));
}
</script>
<form on:submit={onSubmit}>
<label>
<md-switch name="notifications" value="on" selected></md-switch>
Email notifications
</label>
<label>
<md-switch
name="terms"
required
value-missing-label="Please turn this on if you want to proceed."
></md-switch>
Accept the terms
</label>
<md-button variant="filled" type="submit">Save</md-button>
</form>mdInput fires before the flip and is cancelable; mdChange fires
after and cannot be vetoed. To let an external owner hold the state, cancel
mdInput and set selected yourself once the write succeeds.
The two switches below are identical markup. The second one has a listener that
cancels mdInput, waits for a (simulated, 600 ms) save, and only then assigns
selected — so the handle never moves on a write that has not landed:
<md-switch id="sync" aria-label="Cloud sync"></md-switch>
<script type="module">
const sw = document.getElementById('sync');
sw.addEventListener('mdInput', async (e) => {
e.preventDefault(); // block the internal toggle
const wanted = e.detail.selected;
if (await save(wanted)) sw.selected = wanted;
});
</script>import { MdSwitch } from '@awc-ui/react';
import { useState } from 'react';
export function SyncSwitch() {
const [on, setOn] = useState(false);
return (
<MdSwitch
selected={on}
aria-label="Cloud sync"
onMdInput={async (e) => {
e.preventDefault(); // block the internal toggle
const wanted = e.detail.selected;
if (await save(wanted)) setOn(wanted);
}}
/>
);
}import { Component } from '@angular/core';
@Component({
selector: 'app-sync-switch',
template: `
<md-switch [selected]="on" aria-label="Cloud sync" (mdInput)="onInput($event)"></md-switch>
`,
})
export class SyncSwitchComponent {
on = false;
async onInput(e: CustomEvent<{ selected: boolean }>) {
e.preventDefault(); // block the internal toggle
const wanted = e.detail.selected;
if (await this.save(wanted)) this.on = wanted;
}
}<script setup lang="ts">
import { ref } from 'vue';
const on = ref(false);
async function onInput(e: CustomEvent<{ selected: boolean }>) {
e.preventDefault(); // block the internal toggle
const wanted = e.detail.selected;
if (await save(wanted)) on.value = wanted;
}
</script>
<template>
<md-switch :selected="on" aria-label="Cloud sync" @mdInput="onInput" />
</template><script lang="ts">
let on = false;
async function onInput(e: CustomEvent<{ selected: boolean }>) {
e.preventDefault(); // block the internal toggle
const wanted = e.detail.selected;
if (await save(wanted)) on = wanted;
}
</script>
<md-switch selected={on} aria-label="Cloud sync" on:mdInput={onInput} />| Event | Cancelable | Detail | Fires |
|---|---|---|---|
mdInput | yes | { selected } | Before the state changes — preventDefault() blocks the internal toggle |
mdChange | no | { selected } | After the state has committed |
mdValidityChange | no | { valid, validationMessage, flags } | Only on a validity change |
mdInput and mdChange carry the identical payload — { selected: boolean }
— so the difference is not the data, it is the guarantee.
mdInput.detail.selected is a prediction: the state the switch will take if
nothing cancels it. A listener registered after yours can still call
preventDefault(), so a handler that commits on mdInput can commit a flip that
never happened. mdChange fires after the assignment and cannot be vetoed, so it
is the committed fact — calling preventDefault() on it does nothing.
This is the same split the platform uses for <input type="checkbox"> —
click is cancelable and predictive, change is settled — including the part
people forget: neither fires on a programmatic change. Setting
sw.selected = true in code emits nothing, exactly as input.checked = true
emits nothing. If your own code changes the state, your own code already knows.
| You want to… | Listen to |
|---|---|
| Veto the flip (guard, confirm, permission check) | mdInput + preventDefault() |
| Hold the state externally (controlled mode) | mdInput + preventDefault(), then assign selected |
| React to a committed flip (save, analytics, sync) | mdChange |
Track whether a required switch satisfies its form | mdValidityChange |
The detail payloads, for reference — these are inline shapes on the emitters,
not exported type names. @awc-ui/core exports MdSwitchCustomEvent<T> as the
event wrapper:
// mdInput (cancelable) and mdChange (not cancelable){ selected: boolean }
// mdValidityChange{ valid: boolean; validationMessage: string; flags: Record<string, boolean> }Toggle the first switch to watch mdInput land before mdChange. The
second is required, so its validity flips with every toggle — that switch adds
a third line, mdValidityChange, which the first switch never emits because its
validity never moves:
<md-switch id="notify" icons aria-label="Notifications"></md-switch>
<script type="module">
const sw = document.getElementById('notify');
sw.addEventListener('mdInput', (e) => {
// before the flip — e.preventDefault() blocks the internal toggle
console.log('about to become', e.detail.selected);
});
sw.addEventListener('mdChange', (e) => {
console.log('committed', e.detail.selected);
});
sw.addEventListener('mdValidityChange', (e) => {
console.log(e.detail.valid, e.detail.validationMessage);
});
</script>import { MdSwitch } from '@awc-ui/react';
export function NotificationsSwitch() {
return (
<MdSwitch
icons
aria-label="Notifications"
onMdInput={(e) => console.log('about to become', e.detail.selected)}
onMdChange={(e) => console.log('committed', e.detail.selected)}
onMdValidityChange={(e) => console.log(e.detail.valid, e.detail.validationMessage)}
/>
);
}import { Component } from '@angular/core';
@Component({
selector: 'app-notifications-switch',
template: `
<md-switch
icons
aria-label="Notifications"
(mdInput)="onInput($event)"
(mdChange)="onChange($event)"
(mdValidityChange)="onValidity($event)"
></md-switch>
`,
})
export class NotificationsSwitchComponent {
onInput(e: CustomEvent<{ selected: boolean }>) {
console.log('about to become', e.detail.selected);
}
onChange(e: CustomEvent<{ selected: boolean }>) {
console.log('committed', e.detail.selected);
}
onValidity(e: CustomEvent<{ valid: boolean; validationMessage: string }>) {
console.log(e.detail.valid, e.detail.validationMessage);
}
}<script setup lang="ts">
function onInput(e: CustomEvent<{ selected: boolean }>) {
console.log('about to become', e.detail.selected);
}
function onChange(e: CustomEvent<{ selected: boolean }>) {
console.log('committed', e.detail.selected);
}
function onValidity(e: CustomEvent<{ valid: boolean; validationMessage: string }>) {
console.log(e.detail.valid, e.detail.validationMessage);
}
</script>
<template>
<md-switch
icons
aria-label="Notifications"
@mdInput="onInput"
@mdChange="onChange"
@mdValidityChange="onValidity"
/>
</template><script lang="ts">
function onInput(e: CustomEvent<{ selected: boolean }>) {
console.log('about to become', e.detail.selected);
}
function onChange(e: CustomEvent<{ selected: boolean }>) {
console.log('committed', e.detail.selected);
}
function onValidity(e: CustomEvent<{ valid: boolean; validationMessage: string }>) {
console.log(e.detail.valid, e.detail.validationMessage);
}
</script>
<md-switch
icons
aria-label="Notifications"
on:mdInput={onInput}
on:mdChange={onChange}
on:mdValidityChange={onValidity}
/>| Property | Attribute | Type | Default | Reflects |
|---|---|---|---|---|
valueMissingLabel | value-missing-label | string | 'Please turn this on if you want to proceed.' | — |
selected | selected | boolean | false | Yes |
disabled | disabled | boolean | false | Yes |
softDisabled | soft-disabled | boolean | false | Yes |
required | required | boolean | false | Yes |
name | name | string | '' | Yes |
value | value | string | 'on' | — |
icons | icons | boolean | false | — |
showOnlySelectedIcon | show-only-selected-icon | boolean | false | — |
selectedIcon | selected-icon | string | 'check' | — |
unselectedIcon | unselected-icon | string | 'close' | — |
density | density | 0 | -1 | -2 | -3 | -4 | 0 | Yes |
| Method | Parameters |
|---|---|
setFocus() | none |
getValidity() | none |
checkValidity() | none |
reportValidity() | none |
setCustomValidity() | message: string |
| Slot | Description |
|---|---|
selected-icon | — |
unselected-icon | — |
Override on the host element for per-instance theming:
| Property | Description |
|---|---|
--md-switch-track-width | Track width (52px) |
--md-switch-track-height | Track height (32px) — density knob |
--md-switch-handle-size | Selected handle diameter (derived |
--md-switch-track-color | Unselected track fill |
--md-switch-track-outline-color | Unselected track outline |
--md-switch-handle-color | Unselected handle fill |
--md-switch-selected-track-color | Selected track fill |
--md-switch-selected-handle-color | Selected handle fill |
--md-switch-icon-color | Unselected icon color |
--md-switch-selected-icon-color | Selected icon color |
--md-switch-state-layer-color | Hover / focus / press overlay |
--md-switch-focus-ring-color | Focus-ring color |
Style internal elements through shadow DOM with ::part():
| Part | Description |
|---|---|
track | Track container |
state-layer | State-layer overlay (centered on handle) |
handle | Handle / thumb |
icon | Check or close icon |
<label> (name plus hit target) or supply aria-label /
aria-labelledby. There is no default slot.Space toggles; Enter
does not — per the WAI-ARIA switch pattern, Enter stays reserved for form
submission (matching md-checkbox / md-radio).disabled leaves the tab order (tabindex="-1"); soft-disabled stays
focusable (tabindex="0") so keyboard users can discover it. Both are inert to
clicks and keys.icons, state is conveyed by shape as well as colour and handle
position — helpful for colour-vision deficiency.Tab through these: the first three are named three different legitimate ways,
the soft-disabled switch still takes focus, and the disabled one is skipped.
Space toggles whichever one holds focus.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:flex;flex-direction:column;gap:16px;align-items:flex-start;">
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch icons></md-switch>
Wrapped in a label — the text both names it and toggles it
</label>
<div style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);">
<span id="sw-a11y-bt">Bluetooth</span>
<md-switch selected icons aria-labelledby="sw-a11y-bt"></md-switch>
</div>
<md-switch aria-label="Airplane mode"></md-switch>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch soft-disabled></md-switch>
Soft-disabled — still focusable, inert to clicks and keys
</label>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch selected disabled></md-switch>
Disabled — skipped by Tab
</label>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px', alignItems: 'flex-start' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch icons></MdSwitch>
Wrapped in a label — the text both names it and toggles it
</label>
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)' }}>
<span id="sw-a11y-bt">Bluetooth</span>
<MdSwitch selected icons aria-labelledby="sw-a11y-bt"></MdSwitch>
</div>
<MdSwitch aria-label="Airplane mode"></MdSwitch>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch soft-disabled></MdSwitch>
Soft-disabled — still focusable, inert to clicks and keys
</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', color: 'var(--md-sys-color-on-surface)', cursor: 'pointer' }}>
<MdSwitch selected disabled></MdSwitch>
Disabled — skipped by Tab
</label>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:flex;flex-direction:column;gap:16px;align-items:flex-start;">
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch icons></md-switch>
Wrapped in a label — the text both names it and toggles it
</label>
<div style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);">
<span id="sw-a11y-bt">Bluetooth</span>
<md-switch selected icons aria-labelledby="sw-a11y-bt"></md-switch>
</div>
<md-switch aria-label="Airplane mode"></md-switch>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch soft-disabled></md-switch>
Soft-disabled — still focusable, inert to clicks and keys
</label>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch selected disabled></md-switch>
Disabled — skipped by Tab
</label>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:flex;flex-direction:column;gap:16px;align-items:flex-start;">
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch icons></md-switch>
Wrapped in a label — the text both names it and toggles it
</label>
<div style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);">
<span id="sw-a11y-bt">Bluetooth</span>
<md-switch selected icons aria-labelledby="sw-a11y-bt"></md-switch>
</div>
<md-switch aria-label="Airplane mode"></md-switch>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch soft-disabled></md-switch>
Soft-disabled — still focusable, inert to clicks and keys
</label>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch selected disabled></md-switch>
Disabled — skipped by Tab
</label>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:flex;flex-direction:column;gap:16px;align-items:flex-start;">
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch icons></md-switch>
Wrapped in a label — the text both names it and toggles it
</label>
<div style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);">
<span id="sw-a11y-bt">Bluetooth</span>
<md-switch selected icons aria-labelledby="sw-a11y-bt"></md-switch>
</div>
<md-switch aria-label="Airplane mode"></md-switch>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch soft-disabled></md-switch>
Soft-disabled — still focusable, inert to clicks and keys
</label>
<label style="display:flex;align-items:center;gap:12px;color:var(--md-sys-color-on-surface);cursor:pointer;">
<md-switch selected disabled></md-switch>
Disabled — skipped by Tab
</label>
</div>The bare third switch is the one to watch: it renders no text at all, so
aria-label is the only thing giving it a name. Drop it and the switch is
announced as an unlabelled control.
RTL — the handle is positioned with inset-inline-start, so both the track
and the handle’s travel mirror automatically under dir="rtl". Nothing on the
switch needs re-authoring; only the label markup around it has to use logical
spacing. See RTL.
<div dir="rtl"> <label style="display:flex;align-items:center;gap:12px;"> <md-switch selected icons></md-switch> واي فاي </label></div>The same switches in both directions. Nothing is re-authored between the two
rows — only dir changes, and the handle travels the other way on its own:
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>Wi-Fi</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>Bluetooth</label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
</div>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>ltr</span>
<div dir="ltr" style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch selected icons></MdSwitch>Wi-Fi</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch icons></MdSwitch>Bluetooth</label>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>rtl</span>
<div dir="rtl" style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch selected icons></MdSwitch>واي فاي</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch icons></MdSwitch>بلوتوث</label>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>Wi-Fi</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>Bluetooth</label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>Wi-Fi</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>Bluetooth</label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>Wi-Fi</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>Bluetooth</label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
</div>
</div>The switch mirrors itself; the row around it does not. Because there is no
default slot, that row is yours to write — and a physical margin-left pins the
gap to the left edge in both directions, jamming the label against the track
under RTL. Use gap (or margin-inline-start) instead. Both rows below are
dir="rtl":
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">correct</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-inline-start:12px;">بلوتوث</span></label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">wrong</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch selected icons></md-switch><span style="margin-left:12px;">واي فاي</span></label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-left:12px;">بلوتوث</span></label>
</div>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>correct</span>
<div dir="rtl" style={{ display: 'flex', gap: '24px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch selected icons></MdSwitch>واي فاي</label>
<label style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}><MdSwitch icons></MdSwitch><span style={{ marginInlineStart: '12px' }}>بلوتوث</span></label>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>wrong</span>
<div dir="rtl" style={{ display: 'flex', gap: '24px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<label style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}><MdSwitch selected icons></MdSwitch><span style={{ marginLeft: '12px' }}>واي فاي</span></label>
<label style={{ display: 'flex', alignItems: 'center', cursor: 'pointer' }}><MdSwitch icons></MdSwitch><span style={{ marginLeft: '12px' }}>بلوتوث</span></label>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">correct</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-inline-start:12px;">بلوتوث</span></label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">wrong</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch selected icons></md-switch><span style="margin-left:12px;">واي فاي</span></label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-left:12px;">بلوتوث</span></label>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">correct</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-inline-start:12px;">بلوتوث</span></label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">wrong</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch selected icons></md-switch><span style="margin-left:12px;">واي فاي</span></label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-left:12px;">بلوتوث</span></label>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">correct</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-inline-start:12px;">بلوتوث</span></label>
</div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">wrong</span>
<div dir="rtl" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch selected icons></md-switch><span style="margin-left:12px;">واي فاي</span></label>
<label style="display:flex;align-items:center;cursor:pointer;"><md-switch icons></md-switch><span style="margin-left:12px;">بلوتوث</span></label>
</div>
</div>density="-1…-4" is a local override of the inherited data-density, and it
shrinks the track and handle together — the track loses 4px of height and 6px of
width per rung, and the handle is derived from the track height. The glyph does
not taper: it stays a fixed 16px Material Symbol at every rung, so at -4 it
fills the handle entirely. The host also keeps a min-block-size of 48px so the
touch target survives the deeper rungs. Rung 0 is the default — you get it by
setting no density at all — so the top row below carries no attribute. All five
rungs, the same switch, so the taper is visible in one place:
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">0</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch aria-label="Off at the default rung"></md-switch><md-switch selected aria-label="On at the default rung"></md-switch><md-switch selected icons aria-label="On with icons at the default rung"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-1</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-1" aria-label="Off at density -1"></md-switch><md-switch selected density="-1" aria-label="On at density -1"></md-switch><md-switch selected icons density="-1" aria-label="On with icons at density -1"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-2</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-2" aria-label="Off at density -2"></md-switch><md-switch selected density="-2" aria-label="On at density -2"></md-switch><md-switch selected icons density="-2" aria-label="On with icons at density -2"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-3</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-3" aria-label="Off at density -3"></md-switch><md-switch selected density="-3" aria-label="On at density -3"></md-switch><md-switch selected icons density="-3" aria-label="On with icons at density -3"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-4</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-4" aria-label="Off at density -4"></md-switch><md-switch selected density="-4" aria-label="On at density -4"></md-switch><md-switch selected icons density="-4" aria-label="On with icons at density -4"></md-switch></div>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>0</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}><MdSwitch aria-label="Off at the default rung"></MdSwitch><MdSwitch selected aria-label="On at the default rung"></MdSwitch><MdSwitch selected icons aria-label="On with icons at the default rung"></MdSwitch></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-1</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}><MdSwitch density="-1" aria-label="Off at density -1"></MdSwitch><MdSwitch selected density="-1" aria-label="On at density -1"></MdSwitch><MdSwitch selected icons density="-1" aria-label="On with icons at density -1"></MdSwitch></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-2</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}><MdSwitch density="-2" aria-label="Off at density -2"></MdSwitch><MdSwitch selected density="-2" aria-label="On at density -2"></MdSwitch><MdSwitch selected icons density="-2" aria-label="On with icons at density -2"></MdSwitch></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-3</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}><MdSwitch density="-3" aria-label="Off at density -3"></MdSwitch><MdSwitch selected density="-3" aria-label="On at density -3"></MdSwitch><MdSwitch selected icons density="-3" aria-label="On with icons at density -3"></MdSwitch></div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-4</span>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}><MdSwitch density="-4" aria-label="Off at density -4"></MdSwitch><MdSwitch selected density="-4" aria-label="On at density -4"></MdSwitch><MdSwitch selected icons density="-4" aria-label="On with icons at density -4"></MdSwitch></div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">0</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch aria-label="Off at the default rung"></md-switch><md-switch selected aria-label="On at the default rung"></md-switch><md-switch selected icons aria-label="On with icons at the default rung"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-1</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-1" aria-label="Off at density -1"></md-switch><md-switch selected density="-1" aria-label="On at density -1"></md-switch><md-switch selected icons density="-1" aria-label="On with icons at density -1"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-2</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-2" aria-label="Off at density -2"></md-switch><md-switch selected density="-2" aria-label="On at density -2"></md-switch><md-switch selected icons density="-2" aria-label="On with icons at density -2"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-3</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-3" aria-label="Off at density -3"></md-switch><md-switch selected density="-3" aria-label="On at density -3"></md-switch><md-switch selected icons density="-3" aria-label="On with icons at density -3"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-4</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-4" aria-label="Off at density -4"></md-switch><md-switch selected density="-4" aria-label="On at density -4"></md-switch><md-switch selected icons density="-4" aria-label="On with icons at density -4"></md-switch></div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">0</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch aria-label="Off at the default rung"></md-switch><md-switch selected aria-label="On at the default rung"></md-switch><md-switch selected icons aria-label="On with icons at the default rung"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-1</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-1" aria-label="Off at density -1"></md-switch><md-switch selected density="-1" aria-label="On at density -1"></md-switch><md-switch selected icons density="-1" aria-label="On with icons at density -1"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-2</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-2" aria-label="Off at density -2"></md-switch><md-switch selected density="-2" aria-label="On at density -2"></md-switch><md-switch selected icons density="-2" aria-label="On with icons at density -2"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-3</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-3" aria-label="Off at density -3"></md-switch><md-switch selected density="-3" aria-label="On at density -3"></md-switch><md-switch selected icons density="-3" aria-label="On with icons at density -3"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-4</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-4" aria-label="Off at density -4"></md-switch><md-switch selected density="-4" aria-label="On at density -4"></md-switch><md-switch selected icons density="-4" aria-label="On with icons at density -4"></md-switch></div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:grid;grid-template-columns:auto 1fr;gap:14px 16px;align-items:center;">
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">0</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch aria-label="Off at the default rung"></md-switch><md-switch selected aria-label="On at the default rung"></md-switch><md-switch selected icons aria-label="On with icons at the default rung"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-1</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-1" aria-label="Off at density -1"></md-switch><md-switch selected density="-1" aria-label="On at density -1"></md-switch><md-switch selected icons density="-1" aria-label="On with icons at density -1"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-2</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-2" aria-label="Off at density -2"></md-switch><md-switch selected density="-2" aria-label="On at density -2"></md-switch><md-switch selected icons density="-2" aria-label="On with icons at density -2"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-3</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-3" aria-label="Off at density -3"></md-switch><md-switch selected density="-3" aria-label="On at density -3"></md-switch><md-switch selected icons density="-3" aria-label="On with icons at density -3"></md-switch></div>
<span style="inline-size:3.5rem;opacity:.65;font-size:.75rem;font-family:ui-monospace,monospace;">-4</span>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);"><md-switch density="-4" aria-label="Off at density -4"></md-switch><md-switch selected density="-4" aria-label="On at density -4"></md-switch><md-switch selected icons density="-4" aria-label="On with icons at density -4"></md-switch></div>
</div>The two are independent signals, so they compose without any extra wiring —
here a dir="rtl" container at data-density="-2", with one switch tightening
further to -4 and one resetting all the way back to the default rung with an
inline --md-sys-density-scale: 0.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div dir="rtl" data-density="-2" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons density="-4"></md-switch>مضغوط</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons style="--md-sys-density-scale: 0;"></md-switch>افتراضي</label>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div dir="rtl" data-density="-2" style={{ display: 'flex', gap: '24px', flexWrap: 'wrap', alignItems: 'center', color: 'var(--md-sys-color-on-surface)' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch selected icons></MdSwitch>واي فاي</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch icons></MdSwitch>بلوتوث</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch selected icons density="-4"></MdSwitch>مضغوط</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer' }}><MdSwitch selected icons style={{ '--md-sys-density-scale': '0' }}></MdSwitch>افتراضي</label>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div dir="rtl" data-density="-2" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons density="-4"></md-switch>مضغوط</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons style="--md-sys-density-scale: 0;"></md-switch>افتراضي</label>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div dir="rtl" data-density="-2" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons density="-4"></md-switch>مضغوط</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons style="--md-sys-density-scale: 0;"></md-switch>افتراضي</label>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div dir="rtl" data-density="-2" style="display:flex;gap:24px;flex-wrap:wrap;align-items:center;color:var(--md-sys-color-on-surface);">
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons></md-switch>واي فاي</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch icons></md-switch>بلوتوث</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons density="-4"></md-switch>مضغوط</label>
<label style="display:flex;align-items:center;gap:12px;cursor:pointer;"><md-switch selected icons style="--md-sys-density-scale: 0;"></md-switch>افتراضي</label>
</div>Density — each rung trims 4px of track height (floored at 16px) and 6px of width (floored at 28px). See Density.
i18n — the switch ships no text of its own, so a localized switch is simply
a localized label. Translate that label and value-missing-label; the on/off
state is announced from aria-checked, which assistive tech localizes for free.
Keep labels short: M3 requires the text to sit outside the control.
| Custom property | Purpose | Default |
|---|---|---|
--md-switch-track-width / --md-switch-track-height | Track box | 52px / 32px |
--md-switch-handle-size | Handle diameter | 75% of the track height |
--md-switch-track-color | Unselected track fill | surface-container-highest |
--md-switch-track-outline-color | Unselected track border | outline |
--md-switch-selected-track-color | Selected track fill | primary |
--md-switch-handle-color | Unselected handle | outline |
--md-switch-selected-handle-color | Selected handle | on-primary |
--md-switch-icon-color / --md-switch-selected-icon-color | Handle glyph | surface-container-highest / on-primary-container |
--md-switch-state-layer-color | Hover / press overlay | on-surface |
--md-switch-focus-ring-color | Focus ring | secondary |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-switch selected icons aria-label="Error toned" style="--md-switch-selected-track-color: var(--md-sys-color-error); --md-switch-selected-handle-color: var(--md-sys-color-on-error);"></md-switch>
<md-switch selected aria-label="Large track" style="--md-switch-track-width: 72px; --md-switch-track-height: 40px;"></md-switch>
<md-switch aria-label="Tertiary outline" style="--md-switch-track-outline-color: var(--md-sys-color-tertiary); --md-switch-handle-color: var(--md-sys-color-tertiary);"></md-switch>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<MdSwitch selected icons aria-label="Error toned" style={{ '--md-switch-selected-track-color': 'var(--md-sys-color-error)', '--md-switch-selected-handle-color': 'var(--md-sys-color-on-error)' }}></MdSwitch>
<MdSwitch selected aria-label="Large track" style={{ '--md-switch-track-width': '72px', '--md-switch-track-height': '40px' }}></MdSwitch>
<MdSwitch aria-label="Tertiary outline" style={{ '--md-switch-track-outline-color': 'var(--md-sys-color-tertiary)', '--md-switch-handle-color': 'var(--md-sys-color-tertiary)' }}></MdSwitch>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<md-switch selected icons aria-label="Error toned" style="--md-switch-selected-track-color: var(--md-sys-color-error); --md-switch-selected-handle-color: var(--md-sys-color-on-error);"></md-switch>
<md-switch selected aria-label="Large track" style="--md-switch-track-width: 72px; --md-switch-track-height: 40px;"></md-switch>
<md-switch aria-label="Tertiary outline" style="--md-switch-track-outline-color: var(--md-sys-color-tertiary); --md-switch-handle-color: var(--md-sys-color-tertiary);"></md-switch><script setup>
import '@awc-ui/core/define';
</script>
<template>
<md-switch selected icons aria-label="Error toned" style="--md-switch-selected-track-color: var(--md-sys-color-error); --md-switch-selected-handle-color: var(--md-sys-color-on-error);"></md-switch>
<md-switch selected aria-label="Large track" style="--md-switch-track-width: 72px; --md-switch-track-height: 40px;"></md-switch>
<md-switch aria-label="Tertiary outline" style="--md-switch-track-outline-color: var(--md-sys-color-tertiary); --md-switch-handle-color: var(--md-sys-color-tertiary);"></md-switch>
</template><script>
import '@awc-ui/core/define';
</script>
<md-switch selected icons aria-label="Error toned" style="--md-switch-selected-track-color: var(--md-sys-color-error); --md-switch-selected-handle-color: var(--md-sys-color-on-error);"></md-switch>
<md-switch selected aria-label="Large track" style="--md-switch-track-width: 72px; --md-switch-track-height: 40px;"></md-switch>
<md-switch aria-label="Tertiary outline" style="--md-switch-track-outline-color: var(--md-sys-color-tertiary); --md-switch-handle-color: var(--md-sys-color-tertiary);"></md-switch>Every default resolves through an md-sys-color role, so a switch that sets no
custom properties follows the theme on its own:
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch aria-label="Off"></md-switch>
<md-switch selected aria-label="On"></md-switch>
<md-switch selected icons aria-label="On with icons"></md-switch>
<md-switch disabled aria-label="Disabled"></md-switch>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
<MdSwitch aria-label="Off"></MdSwitch>
<MdSwitch selected aria-label="On"></MdSwitch>
<MdSwitch selected icons aria-label="On with icons"></MdSwitch>
<MdSwitch disabled aria-label="Disabled"></MdSwitch>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch aria-label="Off"></md-switch>
<md-switch selected aria-label="On"></md-switch>
<md-switch selected icons aria-label="On with icons"></md-switch>
<md-switch disabled aria-label="Disabled"></md-switch>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch aria-label="Off"></md-switch>
<md-switch selected aria-label="On"></md-switch>
<md-switch selected icons aria-label="On with icons"></md-switch>
<md-switch disabled aria-label="Disabled"></md-switch>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch aria-label="Off"></md-switch>
<md-switch selected aria-label="On"></md-switch>
<md-switch selected icons aria-label="On with icons"></md-switch>
<md-switch disabled aria-label="Disabled"></md-switch>
</div>| Part | Element |
|---|---|
track | The track |
handle | The moving handle |
icon | The glyph inside the handle |
state-layer | Hover / focus / press overlay |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<style>
.parts-switch::part(track) { border-radius: 8px; }
.parts-switch::part(handle) { border-radius: 6px; }
.parts-switch::part(state-layer) { background: var(--md-sys-color-tertiary); }
</style>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch class="parts-switch" aria-label="Squared off"></md-switch>
<md-switch class="parts-switch" selected icons aria-label="Squared on"></md-switch>
</div>import { MdSwitch } from '@awc-ui/react';
export function Demo() {
return (
<>
<style>
.parts-switch::part(track) { border-radius: 8px; }
.parts-switch::part(handle) { border-radius: 6px; }
.parts-switch::part(state-layer) { background: var(--md-sys-color-tertiary); }
</style>
<div style={{ display: 'flex', gap: '20px', flexWrap: 'wrap', alignItems: 'center' }}>
<MdSwitch className="parts-switch" aria-label="Squared off"></MdSwitch>
<MdSwitch className="parts-switch" selected icons aria-label="Squared on"></MdSwitch>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<style>
.parts-switch::part(track) { border-radius: 8px; }
.parts-switch::part(handle) { border-radius: 6px; }
.parts-switch::part(state-layer) { background: var(--md-sys-color-tertiary); }
</style>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch class="parts-switch" aria-label="Squared off"></md-switch>
<md-switch class="parts-switch" selected icons aria-label="Squared on"></md-switch>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<style>
.parts-switch::part(track) { border-radius: 8px; }
.parts-switch::part(handle) { border-radius: 6px; }
.parts-switch::part(state-layer) { background: var(--md-sys-color-tertiary); }
</style>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch class="parts-switch" aria-label="Squared off"></md-switch>
<md-switch class="parts-switch" selected icons aria-label="Squared on"></md-switch>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<style>
.parts-switch::part(track) { border-radius: 8px; }
.parts-switch::part(handle) { border-radius: 6px; }
.parts-switch::part(state-layer) { background: var(--md-sys-color-tertiary); }
</style>
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center;">
<md-switch class="parts-switch" aria-label="Squared off"></md-switch>
<md-switch class="parts-switch" selected icons aria-label="Squared on"></md-switch>
</div>md-switch::part(track) { border-radius: 8px;}md-checkbox ·
md-radio ·
md-button-group ·
md-chip ·
md-slider
md-switchTwo artefacts to give your AI agent so it generates correct UI with this component. The per-component spec answers "how do I use this exact tag?". The main-llm spec answers "which tag should I pick in the first place?".
md-switch spec card
Identity · when to use / when NOT · decision cues · behavioural contract · do/don't · anti-patterns · full API. Paste into your agent when you're implementing with this component.
System-prompt preamble · decision matrix · token reference · page recipes · anti-patterns. Paste into the system prompt at the start of a piece of work.