スイッチコンポーネントのRTL対応:見た目とキーボード操作を両立
WebAwesomeのスイッチコンポーネントに、RTL(右から左)レイアウト向けの対応が追加されました。AndroidやiOSのネイティブスイッチと同様に、RTL環境ではスイッチを左右反転させ、さらにキーボードの矢印キー操作もRTL方向に合わせて動作するようになります。
背景
モバイルOSのネイティブスイッチはRTLロケールで左右を反転する慣習があり、WebAwesomeのスイッチもその挙動に揃える必要がありました。RTL言語(アラビア語やヘブライ語など)のユーザーにとって、スイッチの「オン」が右側にある操作感は直感に反します。AndroidとiOSがどちらもRTL時にスイッチを反転していることを根拠として、本PRはWebAwesomeも同じ振る舞いを採用しています。
これまでは視覚的な反転もキーボード操作のRTL考慮も実装されておらず、RTL環境でのUX上の問題が残っていました。
技術的な変更
変更は switch.styles.ts と switch.ts の2ファイルにまたがり、それぞれ「見た目の反転」と「キーボード操作の反転」を担当します。
CSSによる視覚的反転として、switch.styles.ts に :dir(rtl) 擬似クラスを使った2つのルールが追加されました。
// 未チェック状態(RTL): サムを右端に配置
.switch .thumb:dir(rtl) {
translate: calc((var(--width) - var(--height)) / 2);
}
// チェック済み状態(RTL): サムを左端に配置
.checked .switch .thumb:dir(rtl) {
translate: calc((var(--width) - var(--height)) / -2);
}
LTRでは未チェック時に / -2(左端)、チェック時に / 2(右端)でサムを配置していますが、RTLではこの符号が入れ替わります。ネイティブCSSの :dir() 擬似クラスを使うことで、JavaScriptを介さずにスタイルのみで方向を切り替えています。
キーボード操作のRTL反転として、switch.ts では LocalizeController を導入し、ArrowLeft / ArrowRight キーの動作をRTL環境で逆転させています。
// 変更前
if (event.key === 'ArrowLeft') {
this.checked = false;
}
if (event.key === 'ArrowRight') {
this.checked = true;
}
// 変更後
const isRtl = this.localize.dir() === 'rtl';
if (event.key === 'ArrowLeft') {
this.checked = isRtl; // RTLなら右方向(オン)に相当
}
if (event.key === 'ArrowRight') {
this.checked = !isRtl; // RTLなら左方向(オフ)に相当
}
LTRでは ArrowRight がオン、ArrowLeft がオフですが、RTLではその意味が逆転します。isRtl フラグを使ったシンプルな条件式で、方向の語義とチェック状態の対応を正しく保っています。
設計判断
CSSとJavaScriptの責務を明確に分離した設計が採用されています。視覚的なサムの位置はCSSの :dir(rtl) で宣言的に制御し、キーボードの論理的な方向解釈はJavaScriptの LocalizeController で動的に判定しています。
CSSの :dir() 擬似クラスはHTML要素の dir 属性や言語設定から方向を継承するネイティブ機能であり、コンポーネント内部での明示的なRTL状態管理が不要になります。一方、キーボードイベントはJavaScript側でしか捕捉できないため、LocalizeController.dir() を通じて同じ方向情報を参照する形になっています。両者が同じ情報源(ドキュメントの文字方向)から派生することで、視覚と操作の一貫性が保たれます。
まとめ
本PRは、CSS :dir() 擬似クラスと LocalizeController を組み合わせることで、スタイルとロジックそれぞれに最適な手段でRTL対応を実現しています。ネイティブのモバイルスイッチと同等の直感的な操作感を、最小限のコード変更で達成した実用的な改善です。