Keyboard navigation in `<wa-select>` now keeps the active option in view
<wa-select> がキーボードで操作された際、選択中のオプションがリストボックスの可視領域外に残るバグを修正し、常にスクロールして表示されるようになりました。
背景
選択肢が画面外に残る問題 が Issue #2472 で報告されました。長いオプションリストでタイプ検索や矢印キー操作を行うと、マッチした項目がスクロールされずユーザーが選択結果を確認できない状態でした。開発者は実装上のスクロール呼び出しが欠落していることを特定し、鍵となるユーザー体験の欠如を改善する必要がありました。
技術的な変更
WaSelect コンポーネントにスクロール処理を追加 しました。select.ts のオプション取得後に、ドロップダウンが開いていてリストボックスが非表示でない場合に scrollIntoView を呼び出すロジックを挿入しています。変更前後の差分は以下の通りです。
@@ -715,6 +715,10 @@ export default class WaSelect extends WebAwesomeFormAssociatedElement {
option.current = true;
option.tabIndex = 0;
option.focus({ preventScroll: true });
+
+ if (this.open && !this.listbox.hidden) {
+ scrollIntoView(option, this.listbox, 'vertical', 'auto');
+ }
}
}
テストを追加 して回帰を防止しました。select.test.ts では、listbox.scrollTo をスタブし、擬似的なビューポート情報を設定した上で g, h, a キー入力により "Ghana" がマッチした際に scrollTo が呼び出されることを検証しています。
it('should scroll a type-to-select match into view', async () => {
const el = await fixture<WaSelect>(html`
<wa-select>
<wa-option value="argentina">Argentina</wa-option>
<wa-option value="belgium">Belgium</wa-option>
<wa-option value="canada">Canada</wa-option>
<wa-option value="denmark">Denmark</wa-option>
<wa-option value="egypt">Egypt</wa-option>
<wa-option value="france">France</wa-option>
<wa-option value="ghana">Ghana</wa-option>
</wa-select>
`);
const listbox = el.shadowRoot!.querySelector<HTMLElement>('.listbox')!;
const ghana = el.querySelector<WaOption>('wa-option[value="ghana"]')!;
const scrollTo = sinon.stub(listbox, 'scrollTo');
// …設定省略…
el.focus();
await sendKeys({ press: 'g' });
await sendKeys({ press: 'h' });
await sendKeys({ press: 'a' });
expect(scrollTo.called).to.be.true;
});
設計判断
既存のユーティリティ scrollIntoView を再利用 することで、コードベースへの影響を最小限に抑えました。新しいプロパティやオプションは導入せず、オープン状態かつリストボックスが表示されているケースだけで呼び出す条件分岐を追加した点がポイントです。これにより、従来の WaSelect 使用方法に破壊的変更はなく、既存のアクセシビリティ実装とも整合性が保たれます。さらにテストを追加したことで、将来的なリファクタリングや機能追加に対しても回帰リスクが低減されます。
まとめ
今回の変更は、キーボード操作時に選択肢が常に可視領域にスクロールされるようにしたことで、長いオプションリストでも直感的な操作体験を実現しました。実装は最小限の条件分岐とユーティリティ呼び出しに留め、後方互換性とテストカバレッジを両立させた点が設計上の主な価値です。