カスタムUIの隠れた複雑さ:なぜセマンティックHTMLのボタンを使用すべきなのか
カスタムUIの隠れた複雑さ:なぜセマンティックHTMLのボタンを使用すべきなのか
ネイティブのHTMLボタンをゼロから再構築することは、シシュポスの苦行のようなものです。なぜなら、単純な <button> 要素は、数十年にわたるアクセシビリティ標準、ブラウザの挙動、およびオペレーティングシステムの統合をカプセル化しているからです。カスタム要素を使用してネイティブのボタンを再現するには、開発者はキーボードフォーカスからARIAロール、複雑なフォームバリデーションや送信ロジックに至るまで、すべてを手動で実装しなければなりません。
ネイティブボタンの要件
ネイティブのボタンを真に置き換えるには、カスタムコンポーネントは厳格なUX「法則」とアクセシビリティの要件を満たさなければなりません。MDN、W3C ARIA仕様、およびWCAG 2.2に基づくと、機能的なボタンは以下を満たす必要があります:
- ロールとラベル付け:
buttonロールを持ち、明確なアクセシブルなラベルを持つこと(WCAG SC 4.1.2, 1.3.1)。 - フォーカス管理: キーボードでフォーカス可能であり、フォーカス時に表示されること(WCAG SC 2.4.3, 2.4.7)。
- 入力モダリティ: マウスのクリック、タッチ、スタイラス、およびその他のポインティングデバイスを介してアクティブになること。
- キーボード操作: フォーカス時に、特にSpaceキーとEnterキーでアクティブになること(WCAG SC 2.1.1)。
- フォーム統合:
type(submit,reset,button) をサポートし、フォームバリデーションに参加し、formaction,formmethod,formtargetのような属性を処理すること(WCAG SC 3.3.1)。 - 状態管理:
disabledのような状態をサポートすること(WCAG SC 4.1.2)。 - モダンAPIのサポート: Popover API や Invoker Commands API のような新しいブラウザ機能と統合すること。
実装のギャップ:マークアップから500行のコードへ
ボタンをゼロから構築することは、単純なHTMLタグと、すべてのユーザーのために機能させるために必要な基礎となるロジックとの間の巨大なギャップを明らかにします。
1. アクセシビリティとフォーカス
カスタムタグ(例: <sagan-button>)は、デフォルトで <span> として扱われます。それをボタンとして機能させるには、開発者はアクセシビリティツリーとページのタブ順序に表示されるように、手動で role="button" と tabindex="0" を追加しなければなりません。アイコンボタンの場合、装飾的な絵文字やアイコンを aria-hidden="true" を使用して隠し、絵文字の文字通りの名前をスクリーンリーダーが読み上げるのを避けるために、記述的な aria-label を提供するという追加の作業が必要になります。
2. イベントハンドリングとモダリティ
ネイティブのボタンは、さまざまな入力方法を自動的に処理します。カスタム実装では、マウス、タッチ、スタイラスの操作をカバーするために、mouseup, touchend, および onpointerup を明示的にリッスンする必要があります。さらに、キーボードアクセシビリティには、ネイティブブラウザの期待に合わせるために、keydown (Enterキー) と keyup (Spaceキー) のための個別のロジックが必要です。
3. フォーム関連付けとバリデーション
ネイティブのボタンの最も複雑な側面の一つは、HTMLフォームとの関係です。これを再現するには、カスタム要素は static formAssociated = true を設定し、type, form, formaction, formmethod, formenctype, formnovalidate, formtarget, name, および value を含む属性の膨大なアレイをゲッターとセッターとして実装しなければなりません。
また、Validation API とも統合し、checkValidity() や reportValidity() のようなメソッドを実装し、ElementInternals を介して validity 状態を管理する必要があります。
4. 状態とイベントの順序
カスタムボタンが不安定な挙動をすることを防ぐために、開発者は addEventListener メソッドをラップすること必要があります。これにより、内部ロジック(「active」状態の設定やボタンが disabled かどうかのチェックなど)が、ユーザー定義のイベントリスナーに対して相対的に正しい順序で実行されることを保証します。これがなければ、クリックイベントに対して preventDefault() を呼び出すことが、内部ハンドラーが正しく登録されていない場合、ボタンのデフォルトのアクションを停止させることができない可能性があります。
専門家の知見の統合
開発者の間での議論は、カスタムコンポーネントへの移行の動きが、しばしば使いやすさとアクセシビリティよりも美学を優先してしまうことを浮き彫りにしています。
- 使いやすさ vs. 美学: 一部の開発者は、業界が機能的で高コントラストなネイティブのウィジェットを、より使用速度が遅く直感的でない「フラットな無意味なもの」に替えてしまったと主張しています。
- 「アクセシビリティ・ラケット」: アクセシビリティの不備による訴訟リスクを アクセシビリティ・コンサルタントが、単に複雑な ARIA タグを複雑化させるのではなく、標準的なセマンティックHTMLに書き戻すことで「救済」するという報告があります。
- AIの役割: AI がカスタムコンポーネントのボイラープレートを数分で生成できると示唆する人もいますが、他の人は、AI がアクセシビリティに配慮慮欠けているコードを学習データとして使用していることが多く、潜在的に不適切なアクセシビリティ・パターンを大規模に拡散させる可能性があると警告しています。
- Missing Native Elements (Missing Native Elements): 一般的な反論論点は、サーバーサイド・フィルタリングを備えたコンボボックスのような、ネイティブHTMLが特定の複雑な要素を欠いているために、カスタムコンポーネントが必要になる場合があるというものです。
結論:セマンティックHTMLの重要性
ボタンをゼロから再構築するには、単一の <button> タグが提供する機能のわずか一部を実現するためだけに、JavaScript を約 500 行記述することが必要です。メンテナンスの負担、アクセシビリティの失敗による法的リスク、およびユーザー体験の劣化を招くため、カスタム構築の基本的な UI 要素は非効率的な選択肢です。必要なパターンに対して特定のネイティブ要素が存在しない場合を除き、セマンティックHTMLはウェブ開発におけるゴールドスタンダードであり続けています。