プロンプトとコンテキスト
管理コンソールにおいて、破壊的操作の確認と理由入力フォームが必要です。フローによっては明示的なアクションでのみ閉じる必要があり、他のフローでは Escape や外側クリックで閉じても構いません。キーボード、タッチ、バリデーションの各パスに対応したネイティブ dialog 要素の破棄ポリシーを設計してください。
MDN では closedby の値として none、closerequest、any を定義しています。それぞれ、開発者によるメカニズムのみ、プラットフォームの閉じるリクエスト+開発者メカニズム、または3つすべてのメカニズムです。モーダルダイアログには showModal() を使用し、非モーダルダイアログには show() を使用します。
面接官が見ているポイント
候補者がビジネスリスクを破棄ポリシーにマッピングできるか、モーダルダイアログとポップオーバーを区別できるか、そして Escape、ライトディスミス、close()、requestClose()、method="dialog"、初期フォーカス、フォーカス復帰、フォームバリデーションについて説明できるかを評価します。
最初に確認すべき明確化のための質問
- 破壊的操作の確認が誤って破棄されてもよいか、また未保存の入力内容は保持すべきか?
- Escape や外側クリックはキャンセルと同等か、それとも別の確認が必要か?
- キャンセルボタンは必須フィールドのバリデーションをバイパスすべきか?
- 非対応ブラウザでもまったく同一の破棄挙動を提供する必要があるか?
- ダイアログが閉じたとき、フォーカスはどこに戻るべきか?
30秒の回答フレームワーク
「破壊的操作には showModal() と closedby="closerequest" を併用するか、最も厳格な確認には none を使用し、明示的なキャンセルおよび確定ボタンを配置します。リスクの低い情報パネルには any または popover="auto" を使用できます。method="dialog" を持つフォームは値を返し、キャンセルボタンはバリデーションをバイパスする必要がある場合に formnovalidate を使用できます。意図的な初期フォーカスを設定し、トリガーへフォーカスを復帰させます。機能検出により、明示的なボタンと手動キーボード処理のフォールバックを提供します。」
ステップごとの詳細解説
ステップ 1: モーダルか非モーダルかの選択
showModal() はドキュメントの他の部分を inert(不活性)にし、破壊的操作の確認や必須タスクに適しています。show() は補助パネル向けにページをインタラクティブなままにします。open 属性のみを切り替えても、モーダルのフォーカスと背景のセマンティクスは確立されません。
ステップ 2: リスクを closedby にマッピングする
closedby="none" は開発者が定義した閉じ方のみを許可し、取り返しのつかない確認に適しています。closerequest は Escape やプラットフォームの閉じるリクエストも受け入れます。any は外側クリックによるライトディスミスを追加し、低リスクな情報に適しています。
<dialog id="delete-dialog" closedby="closerequest">
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="confirm">Delete</button>
</form>
</dialog>ステップ 3: Escape、request-close、および close の処理
Escape やプラットフォームのジェスチャーは閉じるリクエストです。requestClose() はリクエストクローズのパスを実行できるため、アプリケーションがそれを確認またはインターセプトできます。close() は直接閉じ、returnValue を設定できます。Escape を削除の確定として解釈してはなりません。
ステップ 4: フォーカスの管理と復帰
モーダルが開いたら、最適な入力フィールド、キャンセルボタン、または見出しにフォーカスを当てます。dialog 要素自体に tabindex を設定しないでください。閉じる際は、トリガーにフォーカスを戻すか、トリガーが削除された場合は安定した代替要素に戻します。
ステップ 5: form method=dialog を意図的に使用する
method="dialog" はネットワークリクエストを送信せずにダイアログを閉じ、フォームコントロールの状態を保持します。ボタンの value が returnValue になります。キャンセルが必須バリデーションをバイパスする必要がある場合は、ユーザーが閉じ込められないよう formnovalidate または明示的な close() を使用します。
ステップ 6: dialog と Popover の違いを理解する
ポップオーバーは非モーダルであり、トップレイヤーに配置されます。popover="auto" はライトディスミスをサポートし、manual は明示的に非表示にされるまで開いたままで、複数の独立したポップオーバーを許可します。モーダルな不活性化が必要な場所にポップオーバーを使用しないでください。
ステップ 7: サポートの検出とフォールバックの提供
HTMLDialogElement、showModal、および closedby のサポートを確認します。サポートされていない場合は、明示的なコントロール、手動の Escape 処理、フォーカス管理、および背景のブロックを提供します。フォールバックは同じキャンセルと確定のコントラクトを維持する必要があります。
ステップ 8: 破棄とアクセシビリティのテスト
Tab、Escape、外側クリック、タッチ、バリデーション失敗、連続オープン、複数モーダル、戻るジェスチャー、およびレガシーブラウザをテストします。クローズ理由(確定、キャンセル、Escape、ライトディスミス)を記録し、スクリーンリーダーを使用して名前付け、状態、フォーカス移動を検証します。
質の高い模範解答
「破壊的操作の確認には showModal() と closedby="closerequest" を使用し、最も厳格なフローでは明示的なキャンセルボタンを伴う none を使用します。低リスクな情報には any または popover="auto" を使用できます。method="dialog" が結果を返し、必要に応じてキャンセルはバリデーションをバイパスできます。初期フォーカスの設定、トリガーへのフォーカス復帰、サポート検出を行い、明示的なコントロールと手動のキーボード/フォーカス処理へとフォールバックします。テストではあらゆる破棄の発生源と支援技術をカバーします。」
よくある間違い
- すべてのダイアログに any を使用する → 破壊的操作が誤って閉じてしまう → closedby をリスクにマッピングする。
- dialog に tabindex を追加する → フォーカスセマンティクスが不正になる → 内部のコントロールまたは見出しにフォーカスする。
- close を requestClose と同様に扱う → 確認ロジックがスキップされる → 要求されたクローズと直接のクローズを区別する。
- 必須フォームのキャンセルボタンでバリデーションを失敗させる → ユーザーが閉じ込められる → formnovalidate または close を使用する。
- モーダルをポップオーバーに置き換える → 背景がインタラクティブなままになる → 不活性化が重要な場合は showModal を使用する。
- マウスのみでテストする → キーボードやタッチのユーザーが離脱できなくなる → Escape、Tab、外側クリック、およびスクリーンリーダーを網羅する。
フォローアップ質問と優れた回答
フォローアップ 1: closerequest と none の本質的な違いは何ですか?
closerequest は開発者コントロールに加えて Escape やプラットフォームの閉じるリクエストを受け付けますが、none は開発者コントロールのみを受け付け、不可逆な操作に適しています。
フォローアップ 2: なぜ showModal は open よりも信頼性が高いのですか?
モーダル状態、背景の不活性化、およびブラウザのフォーカス挙動を確立するためです。open のみを設定すると、非モーダルダイアログが作成されます。
フォローアップ 3: Escape 後の returnValue はどうなりますか?
アプリケーション側で設定しない限り、Escape は送信ボタンの値を表しません。クローズ理由は escape または request-close として個別に記録してください。
フォローアップ 4: キャンセル時に必須バリデーションをバイパスするにはどうすればよいですか?
キャンセル用コントロールに formnovalidate を付与するか close("cancel") を呼び出します。確定側には通常のバリデーションを維持します。
フォローアップ 5: レガシーブラウザ向けのフォールバックは何ですか?
明示的な開閉コントロールを提供し、Escape、フォーカストラップ、背景のブロック、クローズ理由を手動で管理します。ネイティブサポートが復元された際も同じコントラクトテストを維持します。