プロンプトと適用可能なコンテキスト
コンポーネントの状態同期を重複させることなく、ダイアログを開閉する設定ボタンが必要です。カスタムコマンド、キーボードアクセシビリティ、レガシーブラウザ向けフォールバックを含め、command と commandfor が宣言的制御をどのように実現するかを説明してください。
Invoker Commands API を使用すると、ボタンから要素の ID をターゲットにして組み込みアクションを呼び出したり、カスタムの command イベントを発火させたりできます。これは誰が呼び出し、どの要素がアクションを実行するかを HTML 上で表現しますが、ビジネスステートマシン、パーミッションチェック、または非対応ブラウザのフォールバックを代替するものではありません。
面接官が評価するポイント
commandfor の同一ツリー内ターゲット要件、組み込みコマンドとカスタムコマンドの違い、イベントのキャンセルとデフォルト動作、キーボードおよびフォーカス管理、そして新しい属性を実行時における唯一の保証とみなすのではなくプログレッシブエンハンスメントを適用できているかを網羅してください。
質問の明確化
ターゲットがモーダルダイアログ、非モーダルポップオーバー、通常の要素のいずれであるか、ボタンとターゲットが同一ツリーを共有しているか、送信バリデーションが必要か、どのブラウザを対象とするかを確認します。また、初期フォーカス、Escape キーの動作、フォーカスの復帰、カスタムコマンドにビジネス認可が必要かどうかも明確にします。
30秒の回答フレームワーク
「commandfor でターゲットを指定し、表示・非表示・切り替えには組み込みコマンドを使用します。ビジネスアクションにはカスタムコマンドイベントを使用し、コントローラーが状態を検証して必要に応じてデフォルト動作を抑止します。ネイティブボタンはキーボード操作が可能ですが、初期フォーカス、Escape、フォーカス復帰、アクセシブルな名前を引き続き検証します。レガシーブラウザ向けには同じステートマシンを呼び出す JavaScript やコンポーネントのフォールバックを保持し、ネイティブパスとフォールバックパスで同等の動作を維持します。」
ステップバイステップの詳細解説
ステップ 1: ボタンとターゲットのリレーションを宣言する
commandfor の値はターゲット要素の ID であり、両方の要素が同一ツリー内に存在する必要があります。ボタンの command の値でアクションを選択します。これにより、手動での DOM クエリや状態同期の重複なしに、静的 HTML で制御を表現できます。
ステップ 2: 組み込みコマンドを優先する
ダイアログやポップオーバーには、表示、非表示、切り替えを行うブラウザコマンドが定義されています。ネイティブの動作はトップレイヤー、ライトディスミス、フォーカスルールと連携できます。既存のセマンティクスをカスタム文字列で再実装しないでください。
<button commandfor="settings" command="show-modal">
Open settings
</button>
<dialog id="settings">
<button commandfor="settings" command="close">Close</button>
</dialog>ステップ 3: カスタムコマンドイベントを処理する
-- で始まるカスタムコマンドは、ターゲットとコマンド値を含む command イベントを発火します。ハンドラーはオリジンと現在の状態を検証し、必要に応じて preventDefault() を呼び出してビジネスアクションを実行する必要があります。カスタムコマンド自体が表示・非表示を自動的に変更することはありません。
ステップ 4: 認可とバリデーションはビジネスコード内に保持する
宣言的な呼び出しは意図を表現するだけであり、認可、フォームバリデーション、非同期永続化をバイパスすることはできません。ターゲットのコントローラーはアクションを実行する前にパーミッション、データバージョン、現在の状態を確認し、HTML をセキュリティ境界とみなすのではなく回復可能なエラーを返すべきです。
ステップ 5: フォーカスとキーボードの動作を設計する
ネイティブのダイアログやポップオーバーについては、初期フォーカス、Escape による閉じる動作、フォーカス復帰、アクセシブルな名前を検証します。通常の要素にはこれらのセマンティクスが自動的には付与されません。カスタムターゲットには明示的なキーボードモデルとフォーカスポリシーが必要です。
ステップ 6: キャンセルと競合状態を処理する
複数のボタンが同時にコマンドを発行する可能性があります。重複したオープン、送信、または閉じた後の古い非同期再オープンを防ぐために、ターゲットの現在の状態を確認してください。エラーによって不正な ARIA やフォーカス状態が残らないよう、非同期のビジネス状態を表示状態から分離して管理します。
ステップ 7: レガシーブラウザ向けフォールバックを提供する
commandfor をサポートしていないブラウザは属性を無視するため、通常のボタンリスナーまたはコンポーネントバインディングを維持します。動作の乖離を防ぐため、同じコマンドハンドラーとアクセシビリティテストを再利用してください。
ステップ 8: ネイティブパスとフォールバックパスをテストする
マウス、キーボード、スクリーンリーダー、Escape、フォーカス復帰、重複コマンド、デフォルトキャンセルの動作、権限拒否、非同期エラーをテストします。組み込みコマンド、カスタムイベント、ターゲットタイプに対してブラウザマトリックスを使用してください。MDN Baseline の表示はすべてのランタイムでの動作を保証するものではありません。
高品質な回答サンプル
同一ツリー内のダイアログを指す commandfor を静的ボタンに設定し、基本動作には組み込みの show-modal および close コマンドを使用します。ビジネスロジックにはカスタムコマンドイベントを使用し、そのハンドラーで認可、フォームのバージョン、現在の状態を確認してデフォルト動作を抑止できるようにします。カスタムコマンド自体は表示の切り替えを行いません。ネイティブダイアログはモーダルセマンティクスを提供しますが、フォーカス、Escape、フォーカス復帰、アクセシブルな名前は別途テストします。新しい属性を無視する古いブラウザ向けには、同じコマンドハンドラーを呼び出すフォールバックリスナーを用意します。最後に、キーボードとスクリーンリーダーの動作、同時クリック、非同期失敗、両パスにわたるブラウザマトリックスをテストします。
よくある間違い
commandfor が Shadow DOM やドキュメント全体を横断して検索すると想定すること
仕様では同一ツリー内にターゲット ID があることが求められます。ツリー間またはドキュメント間の制御には、異なる ID ではなく、明示的なコンポーネントプロトコルやメッセージングが必要です。
すべてのカスタムコマンドにデフォルト動作があると想定すること
カスタムコマンドは主にイベントを発行するだけです。ハンドラー側で状態変更を実装し、デフォルト動作をキャンセルする条件を定義する必要があります。
マウスクリックのみをテストすること
キーボード到達性、フォーカス順序、Escape キー、スクリーンリーダーへのフィードバックは、インタラクション仕様の一部です。視覚的に開いている状態だけでは、アクセシビリティの十分な証明にはなりません。
フォローアップの質問と回答
ターゲットを動的に置き換えた場合、commandfor の再バインドは必要ですか?
置き換えられた要素が同じ ID を維持し、同一ツリー内に留まる場合は、宣言的リレーションをそのまま継続できます。ただし、コントローラー側でフォーカスやビジネス状態をリセットする必要があります。ID が重複している場合やターゲットが存在しない場合は、コマンドをブロックして診断可能な状態を公開すべきです。
カスタムの非同期コマンドによる重複送信を防ぐにはどうすればよいですか?
リクエスト状態や冪等性キーを使用して同じアクションをロックし、ボタンをビジー状態に設定して、キャンセルまたは再試行のパスを確保します。完了後はターゲットがまだ存在することを確認し、古い結果によって新しいセッションが変更されないようにします。
HTML コマンドのみを使用せず、JavaScript コンポーネントを維持すべきなのはどのような場合ですか?
ツリー間の連携、複雑なアニメーション、非同期ステートマシン、またはレガシーブラウザの広範なサポートが必要なインタラクションにはコンポーネントを使用します。command はプログレッシブエンハンスメントのエントリーポイントとして依然として有用ですが、ビジネスの境界はテスト可能な状態に保つ必要があります。