フォームの入力欄に最初からカーソルを当てたり、エラーのあった項目へ移動させたりと、JavaScriptで特定の要素にフォーカスを当てたい場面はよくあります。
基本は要素を取得して focus() を呼ぶだけですが、読み込み時のタイミング、スクロールの制御、フォーカスできない要素への対応など、実務で役立つポイントを合わせて解説します。
element.focus() を呼ぶだけです。読み込み時は autofocus 属性か DOMContentLoaded 内で実行、スクロールを抑えたいときは focus({ preventScroll: true })、フォーカスできない要素には tabindex を付けます。要素を選んで focus() する(基本)
まず対象の要素を取得し、focus() を呼びます。取得には getElementById やCSSセレクタの querySelector を使います。
// IDで取得
document.getElementById("username").focus();
// CSSセレクタで取得(最初の1つ)
document.querySelector(".search-input").focus();
// 属性で取得
document.querySelector('[name="email"]').focus();
要素の取得方法そのものはquerySelectorの使い方やgetElementById・querySelectorの使い分けで詳しく解説しています。ここからはフォーカス特有のポイントを見ていきます。
ページ読み込み時にフォーカスする
ページを開いた瞬間に入力欄へフォーカスを当てる方法は2つあります。JavaScript不要の autofocus 属性と、DOMContentLoaded 内での focus() です。
<input type="text" id="username" autofocus>
document.addEventListener("DOMContentLoaded", () => {
document.getElementById("username").focus();
});
autofocus は1ページに1つだけにします。また、スマートフォンでは意図せずキーボードが開くことがあるため、モバイルでは使いどころに注意してください。条件によって出し分けたい場合はJavaScriptの方が柔軟です。フォーカス時のスクロールを制御する
focus() は対象が画面外にあると自動でスクロールします。これを抑えたいときは preventScroll オプションを使います。逆に、確実に見える位置までスクロールしたいときは scrollIntoView を組み合わせます。
const input = document.getElementById("target");
// フォーカス時の自動スクロールを抑制
input.focus({ preventScroll: true });
// フォーカス後に中央へ滑らかにスクロール
input.focus();
input.scrollIntoView({ behavior: "smooth", block: "center" });
フォーカスできない要素にフォーカスする(tabindex)
<div> や <p> など、通常はフォーカスできない要素にfocus() を呼んでも効きません。tabindex 属性を付けるとフォーカス可能になります。
<!-- tabindex="-1": スクリプトからフォーカス可能(Tabキーの順序には入らない) --> <div id="notice" tabindex="-1">通知メッセージ</div>
document.getElementById("notice").focus(); // tabindex があれば効く
tabindex="-1" はスクリプトからのみフォーカス可能(Tabキーでは飛ばされる)、tabindex="0" はTabキーの順序にも加わります。通知やエラーメッセージへフォーカスを移してスクリーンリーダーに読ませる、といった用途で使います。
実用:最初のエラー項目にフォーカスする
フォーム送信時に入力エラーがあったら、最初のエラー項目へフォーカスを移すと親切です。HTML5バリデーションの :invalid 疑似クラスを querySelector で拾います。
const form = document.getElementById("form");
form.addEventListener("submit", (event) => {
const firstInvalid = form.querySelector(":invalid");
if (firstInvalid) {
event.preventDefault(); // 送信を止める
firstInvalid.focus(); // 最初のエラー項目へ移動
}
});
これには required や type="email" などのバリデーション属性が設定されている必要があります。フォーム入力の監視全般はフォーム入力をリアルタイムで監視する方法も参考になります。
フォーカス状態を扱う(activeElement / blur / イベント)
今どの要素がフォーカスされているかは document.activeElement で分かります。フォーカスを外すには blur()、フォーカスの変化は focus / blur イベントで検知します。
// 今フォーカスされている要素
console.log(document.activeElement);
// フォーカスを外す
document.getElementById("username").blur();
// フォーカスの出入りを検知
const input = document.getElementById("username");
input.addEventListener("focus", () => console.log("フォーカスされた"));
input.addEventListener("blur", () => console.log("外れた"));
focus / blur はバブリングしませんが、親要素でまとめて監視したい場合はバブリングする focusin / focusoutを使います。
よくある質問(FAQ)
element.focus() を呼びます。モーダルを開いたときや、エラー発生時に問題のフィールドへフォーカスを移す際によく使います。DOMContentLoaded イベント内で focus() を呼ぶか、HTML属性の autofocus を対象要素に設定します。autofocus はモバイルで予期しないキーボード表示が起きることがあるため注意が必要です。element.focus({ preventScroll: true }) を使うと、フォーカス時の自動スクロールを抑制できます。逆に確実に見せたいときは、フォーカス後に element.scrollIntoView({ behavior: "smooth" }) を呼びます。tabindex 属性を付けます。tabindex="-1" でスクリプトからフォーカス可能(Tab順には入らない)、tabindex="0" でTabキーの順序にも加わります。まとめ
要素のフォーカスは element.focus() が基本で、対象は getElementById や querySelector で取得します。
読み込み時は autofocus か DOMContentLoaded、スクロールを抑えるなら preventScroll、フォーカスできない要素には tabindex、と状況に応じて使い分けましょう。最初のエラー項目へのフォーカスや、activeElement での状態取得まで押さえると、使いやすく親切なフォームが作れます。
