やりたいこと
Vue.jsでモーダルダイアログ表示中にTab移動した時、フォーカスがモーダルダイアログ外に行かないようにしたい。
※ただし、Webページ外(ブラウザのアドレスバーなど)からのTab移動は除く。
成果物
Before
Tab移動すると、ダイアログ外に移動してしまう。
移動順序: テキストボックス --> OKボタン --> キャンセルボタン --> アドレスバー --> 背後のテキストボックス
After
移動順序: テキストボックス --> OKボタン --> キャンセルボタン --> テキストボックス
実装方針
ダイアログの要素外に空のdiv要素を用意し、そこにフォーカスが当たったら、最初の要素にフォーカスを移動する。
1. 空のdiv要素の配置
Tab
キーもしくはShift + Tab
キーでのフォーカス移動に対応するため、ダイアログの要素の前後に空のdiv要素を配置する。
<div tabindex="0" class="dummy"></div> <!-- モーダルダイアログの要素 --> <div class="modal-body"> <input class="input-text" type="text" v-model="comment" ref="modalComment" /> </div> <div tabindex="0" class="dummy"></div>
2. 空のdiv要素にフォーカスが移動したことを検知する
モーダルダイアログのコンポーネントが表示されているときのみフォーカスを検知する必要がある。Vueコンポーネントのライフサイクルに合わせて、イベント登録/破棄を行う。
// モーダルダイアログのSFCファイル created() { document.addEventListener("focusin", this.checkFocus, false); }, beforeDestroy() { document.removeEventListener("focusin", this.checkFocus, false); }
3. 最初の要素にフォーカスを移動する
モーダルダイアログのフォーカス可能な最初の要素にフォーカス移動する。
// モーダルダイアログのSFCファイル methods: { checkFocus: function(ev) { if (ev.target !== null && ev.target.className == 'dummy') { this.$refs.modalComment.focus(); } } }
所感
調査段階では、tabindex=-1
にする方法も考えたが、この方法はDOM操作など影響範囲が少ないのでスマート。