似たようなスクリプトは探せば結構あるのですが、問題が多いので1から作りました。
button上でenter押下時も移動するようにしていますが、実際のアプリに組み込んで動作確認したら動作を変えるかもしれません。
- enterキー押下時に次項目へ移動するjavascript(jQuery利用)
- フォーカス移動概要
- tabindex順に移動します(tabindex1以上⇒tabindex未指定の順)
- tabindexがマイナスの項目へは移動しません
- tabindexがマイナスの項目から移動する場合は、直近前後の項目へ移動します。
- 通常移動しない項目やにtabindexを付けると移動可能になることを考慮
- 上記に関連して、フォーカス移動可能な項目が入れ子になっていても移動できる
- anchorは移動対象から外しています。移動しても、Enterでリンク先に移動してしまい不便なためです。
- textareaは移動対象ですが、Enterでは次へ移動するため改行できません。 ⇒Ctrl+Enterで改行できるように制御しています。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script>
$(() => {
// :focusable はマイナスのtabindexを含む
// ⇒enter時に次項目へ移動するためのイベント対象のため含めている。
const elements = ':focusable:not(a)';
$(elements).keypress((e) => {
if (e.key === 'Enter') {
// submitしない
e.preventDefault();
// focus可能な項目が入れ子になっている場合、targetのみで処理する
e.stopPropagation();
// tabindex順に移動するためソート
let sortedList = $(elements).sort((a,b) => {
if(a.tabIndex && b.tabIndex) {
return a.tabIndex - b.tabIndex;
} else if(a.tabIndex && !b.tabIndex) {
return -1;
} else if(!a.tabIndex && b.tabIndex) {
return 1;
}
return 0;
});
if (e.target.tabIndex < 0) {
// tabindexがマイナスの場合、DOM上で次の項目へ移動するためソート前の項目から検索する
sortedList = elements;
}
// 現在の項目位置から、移動先を取得する
const index = $(sortedList).index(e.target);
const nextFilter = e.shiftKey ? `:lt(${index}):last` : `:gt(${index}):first`;
const nextTarget = $(sortedList).filter(nextFilter);
// shift + enterでtagindexがマイナスの項目へ移動するのを防ぐ
if (!nextTarget.length || nextTarget[0].tabIndex < 0) return;
// フォーカス移動+文字列選択
nextTarget.focus();
if (typeof nextTarget.select === 'function') nextTarget.select();
}
});
});
</script>
- input, button, select, textarea, aがフォーカス移動可能なelement
- 上記以外でも、tabindex属性を与えると移動対象となる
- disabled、見えない項目は移動対象外
- tabindex(1以上)の順に移動 ⇒ 最大まで行ったらtabindex未指定(or 0,空白)をDOM出現順に移動 ⇒ URL入力欄に移動
- 同じtabindexが複数ある場合はDOM出現順に移動
tabindex=0
やtabindex=""
は未指定と同じ扱い- tabindexがマイナスの項目には移動しない。
- tabindexがマイナスの項目にフォーカスがある場合、次項目はDOM出現順に移動可能な項目へ移動
- Shiftを押下時は逆順に移動
- ラジオボタンは同じnameを持つ場合、グループ化される。 ・・・【制御がややこしいため、未サポート】
- グループがチェックを持つ場合は、そこへフォーカスする。
- チェックがない場合は、グループの先頭にフォーカスする。
- 同一グループ内で異なるtabindexを持つ場合
- チェックがなければ、それぞれのtabindex毎にグループ化されるような動き
- チェックがあれば、チェックがある箇所のみが移動対象となる
- タブ移動時、ラジオボタンは同一nameでグループ化されるのがTabでの動作ですが、そこまで細かい制御はできていません。
https://html.spec.whatwg.org/multipage/interaction.html#sequential-focus-navigation
セレクタで「:focusable」「:tabbable」があるが、tabindexの順番まで考慮して並べ替えはしてくれない模様。 ⇒ 画面の項目順に移動する前提であれば使える。