Switch
ユーザーが2つの状態(オンとオフ)を切り替えることができるコントロール。
🤖 AI Implementation Guideデモ
アクセシビリティ
WAI-ARIA ロール
-
switch- ユーザーがオン/オフの2つの値のいずれかを選択できる入力ウィジェット
WAI-ARIA switch role (opens in new tab)
WAI-ARIA ステート
aria-checked
スイッチの現在のチェック状態を示します。
| 値 | true | false |
| 必須 | はい(switchロールの場合) |
| デフォルト | initialChecked プロパティ(デフォルト: false) |
| 変更トリガー | クリック、Enter、Space |
| リファレンス | aria-checked (opens in new tab) |
aria-disabled
スイッチが認識可能だが無効化されていることを示します。
| 値 | true | undefined |
| 必須 | いいえ(無効化時のみ) |
| リファレンス | aria-disabled (opens in new tab) |
キーボードサポート
| キー | アクション |
|---|---|
| Space | スイッチの状態を切り替え(オン/オフ) |
| Enter | スイッチの状態を切り替え(オン/オフ) |
アクセシブルな名前
スイッチにはアクセシブルな名前が必要です。以下の方法で提供できます:
- 表示されるラベル(推奨) - スイッチの子要素のコンテンツがアクセシブルな名前を提供
-
aria-label- スイッチに非表示のラベルを提供 -
aria-labelledby- 外部要素をラベルとして参照
ビジュアルデザイン
この実装は、色のみに依存せず状態を示すことでWCAG 1.4.1(色の使用)に準拠しています:
- つまみの位置 - 左 = オフ、右 = オン
- チェックマークアイコン - スイッチがオンの時のみ表示
- 強制カラーモード - Windowsハイコントラストモードでのアクセシビリティのためシステムカラーを使用
ソースコード
Switch.astro
---
/**
* APG Switch Pattern - Astro Implementation
*
* A control that allows users to toggle between two states: on and off.
* Uses Web Components for client-side interactivity.
*
* @see https://www.w3.org/WAI/ARIA/apg/patterns/switch/
*/
export interface Props {
/** Initial checked state */
initialChecked?: boolean;
/** Whether the switch is disabled */
disabled?: boolean;
/** Additional CSS class */
class?: string;
}
const { initialChecked = false, disabled = false, class: className = '' } = Astro.props;
---
<apg-switch class={className}>
<button
type="button"
role="switch"
class="apg-switch"
aria-checked={initialChecked}
aria-disabled={disabled || undefined}
disabled={disabled}
>
<span class="apg-switch-track">
<span class="apg-switch-icon" aria-hidden="true">
<svg viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg">
<path
d="M10.28 2.28a.75.75 0 00-1.06-1.06L4.5 5.94 2.78 4.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.06 0l5.25-5.25z"
fill="currentColor"></path>
</svg>
</span>
<span class="apg-switch-thumb"></span>
</span>
{
Astro.slots.has('default') && (
<span class="apg-switch-label">
<slot />
</span>
)
}
</button>
</apg-switch>
<script>
class ApgSwitch extends HTMLElement {
private button: HTMLButtonElement | null = null;
private rafId: number | null = null;
connectedCallback() {
this.rafId = requestAnimationFrame(() => this.initialize());
}
private initialize() {
this.rafId = null;
this.button = this.querySelector('button[role="switch"]');
if (!this.button) {
console.warn('apg-switch: button element not found');
return;
}
this.button.addEventListener('click', this.handleClick);
this.button.addEventListener('keydown', this.handleKeyDown);
}
disconnectedCallback() {
if (this.rafId !== null) {
cancelAnimationFrame(this.rafId);
this.rafId = null;
}
this.button?.removeEventListener('click', this.handleClick);
this.button?.removeEventListener('keydown', this.handleKeyDown);
this.button = null;
}
private toggle() {
if (!this.button || this.button.disabled) return;
const currentChecked = this.button.getAttribute('aria-checked') === 'true';
const newChecked = !currentChecked;
this.button.setAttribute('aria-checked', String(newChecked));
this.dispatchEvent(
new CustomEvent('change', {
detail: { checked: newChecked },
bubbles: true,
})
);
}
private handleClick = () => {
this.toggle();
};
private handleKeyDown = (event: KeyboardEvent) => {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
this.toggle();
}
};
}
if (!customElements.get('apg-switch')) {
customElements.define('apg-switch', ApgSwitch);
}
</script> 使い方
使用例
---
import Switch from './Switch.astro';
---
<Switch initialChecked={false}>
Enable notifications
</Switch>
<script>
// Listen for change events
document.querySelector('apg-switch')?.addEventListener('change', (e) => {
console.log('Checked:', e.detail.checked);
});
</script> API
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
initialChecked | boolean | false | 初期のチェック状態 |
disabled | boolean | false | スイッチが無効かどうか |
class | string | "" | 追加のCSSクラス |
カスタムイベント
| イベント | 詳細 | 説明 |
|---|---|---|
change | { checked: boolean } | スイッチの状態が変更されたときに発火 |
スロット
| スロット | 説明 |
|---|---|
default | スイッチのラベルコンテンツ |
テスト
テストは、キーボードインタラクション、ARIA属性、アクセシビリティ要件全体でAPG準拠を検証します。Switchコンポーネントは2層のテスト戦略を採用しています。
テスト戦略
ユニットテスト(Testing Library)
フレームワーク固有のテストライブラリを使用してコンポーネントのレンダリング出力を検証します。これらのテストは正しいHTML構造とARIA属性を確認します。
- ARIA属性(role="switch"、aria-checked)
- キーボードインタラクション(Space、Enter)
- 無効状態の処理
- jest-axeによるアクセシビリティ検証
E2Eテスト(Playwright)
すべてのフレームワークで実際のブラウザ環境でコンポーネントの動作を検証します。これらのテストはインタラクションとフレームワーク間の一貫性をカバーします。
- クリックとキーボードのトグル動作
- ライブブラウザでのARIA構造
- 無効状態のインタラクション
- axe-coreによるアクセシビリティスキャン
- フレームワーク間の一貫性チェック
テストカテゴリ
高優先度: APG キーボードインタラクション(Unit + E2E)
| テスト | 説明 |
|---|---|
Space key | スイッチの状態を切り替え |
Enter key | スイッチの状態を切り替え |
Tab navigation | Tabキーでスイッチ間をフォーカス移動 |
Disabled Tab skip | 無効化されたスイッチはTab順序でスキップされる |
Disabled key ignore | 無効化されたスイッチはキー押下を無視する |
高優先度: APG ARIA 属性(Unit + E2E)
| テスト | 説明 |
|---|---|
role="switch" | 要素にswitchロールが設定されている |
aria-checked initial | 初期状態が aria-checked="false" |
aria-checked toggle | クリックで aria-checked 値が変更される |
type="button" | 明示的なボタンタイプでフォーム送信を防止 |
aria-disabled | 無効化されたスイッチは aria-disabled="true" を持つ |
中優先度: アクセシビリティ(Unit + E2E)
| テスト | 説明 |
|---|---|
axe violations | WCAG 2.1 AA違反なし(jest-axe経由) |
Accessible name (children) | スイッチが子要素のコンテンツから名前を持つ |
aria-label | aria-label経由でアクセシブルな名前 |
aria-labelledby | 外部要素経由でアクセシブルな名前 |
低優先度: HTML属性継承(Unit)
| テスト | 説明 |
|---|---|
className merge | カスタムクラスがコンポーネントクラスとマージされる |
data-* attributes | カスタムdata属性が引き継がれる |
低優先度: フレームワーク間の一貫性(E2E)
| テスト | 説明 |
|---|---|
All frameworks have switch | React、Vue、Svelte、Astroすべてがスイッチ要素をレンダリング |
Toggle on click | すべてのフレームワークでクリック時に正しくトグル |
Consistent ARIA | すべてのフレームワークで一貫したARIA構造 |
テストツール
- Vitest (opens in new tab) - ユニットテストランナー
- Testing Library (opens in new tab) - フレームワーク別テストユーティリティ(React、Vue、Svelte)
- Playwright (opens in new tab) - E2Eテスト用ブラウザ自動化
- axe-core/playwright (opens in new tab) - E2Eでの自動アクセシビリティテスト
完全なドキュメントは testing-strategy.md (opens in new tab) を参照してください。
リソース
- WAI-ARIA APG: Switch パターン (opens in new tab)
- AI Implementation Guide (llm.md) (opens in new tab) - ARIA specs, keyboard support, test checklist