【JavaScript】特定の要素をフォーカスする方法

フォームの入力欄に最初からカーソルを当てたり、エラーのあった項目へ移動させたりと、JavaScriptで特定の要素にフォーカスを当てたい場面はよくあります。

基本は要素を取得して focus() を呼ぶだけですが、読み込み時のタイミング、スクロールの制御、フォーカスできない要素への対応など、実務で役立つポイントを合わせて解説します。

この記事の結論:要素を取得して element.focus() を呼ぶだけです。読み込み時は autofocus 属性か DOMContentLoaded 内で実行、スクロールを抑えたいときは focus({ preventScroll: true })、フォーカスできない要素には tabindex を付けます。
スポンサーリンク

要素を選んで focus() する(基本)

まず対象の要素を取得し、focus() を呼びます。取得には getElementById やCSSセレクタの querySelector を使います。

JavaScript:要素を取得してフォーカス
// 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() です。

HTML:autofocus属性(JS不要)
<input type="text" id="username" autofocus>
JavaScript:DOM構築後にフォーカス
document.addEventListener("DOMContentLoaded", () => {
  document.getElementById("username").focus();
});
autofocusの注意:autofocus1ページに1つだけにします。また、スマートフォンでは意図せずキーボードが開くことがあるため、モバイルでは使いどころに注意してください。条件によって出し分けたい場合はJavaScriptの方が柔軟です。

フォーカス時のスクロールを制御する

focus() は対象が画面外にあると自動でスクロールします。これを抑えたいときは preventScroll オプションを使います。逆に、確実に見える位置までスクロールしたいときは scrollIntoView を組み合わせます。

JavaScript:スクロールの制御
const input = document.getElementById("target");

// フォーカス時の自動スクロールを抑制
input.focus({ preventScroll: true });

// フォーカス後に中央へ滑らかにスクロール
input.focus();
input.scrollIntoView({ behavior: "smooth", block: "center" });

フォーカスできない要素にフォーカスする(tabindex)

<div><p> など、通常はフォーカスできない要素にfocus() を呼んでも効きません。tabindex 属性を付けるとフォーカス可能になります。

HTML
<!-- tabindex="-1": スクリプトからフォーカス可能(Tabキーの順序には入らない) -->
<div id="notice" tabindex="-1">通知メッセージ</div>
JavaScript
document.getElementById("notice").focus(); // tabindex があれば効く

tabindex="-1" はスクリプトからのみフォーカス可能(Tabキーでは飛ばされる)、tabindex="0" はTabキーの順序にも加わります。通知やエラーメッセージへフォーカスを移してスクリーンリーダーに読ませる、といった用途で使います。

実用:最初のエラー項目にフォーカスする

フォーム送信時に入力エラーがあったら、最初のエラー項目へフォーカスを移すと親切です。HTML5バリデーションの :invalid 疑似クラスを querySelector で拾います。

JavaScript:最初のエラー項目へフォーカス
const form = document.getElementById("form");

form.addEventListener("submit", (event) => {
  const firstInvalid = form.querySelector(":invalid");
  if (firstInvalid) {
    event.preventDefault();      // 送信を止める
    firstInvalid.focus();        // 最初のエラー項目へ移動
  }
});

これには requiredtype="email" などのバリデーション属性が設定されている必要があります。フォーム入力の監視全般はフォーム入力をリアルタイムで監視する方法も参考になります。

フォーカス状態を扱う(activeElement / blur / イベント)

今どの要素がフォーカスされているかは document.activeElement で分かります。フォーカスを外すには blur()、フォーカスの変化は focus / blur イベントで検知します。

JavaScript:状態の取得とイベント
// 今フォーカスされている要素
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)

QJavaScriptで特定の要素にフォーカスを当てるには?
A要素を取得して element.focus() を呼びます。モーダルを開いたときや、エラー発生時に問題のフィールドへフォーカスを移す際によく使います。
Qページ読み込み時に自動でフォーカスするには?
ADOMContentLoaded イベント内で focus() を呼ぶか、HTML属性の autofocus を対象要素に設定します。autofocus はモバイルで予期しないキーボード表示が起きることがあるため注意が必要です。
Qフォーカス時に画面がスクロールしないようにするには?
Aelement.focus({ preventScroll: true }) を使うと、フォーカス時の自動スクロールを抑制できます。逆に確実に見せたいときは、フォーカス後に element.scrollIntoView({ behavior: "smooth" }) を呼びます。
Qdivなどフォーカスできない要素にフォーカスするには?
Atabindex 属性を付けます。tabindex="-1" でスクリプトからフォーカス可能(Tab順には入らない)、tabindex="0" でTabキーの順序にも加わります。

まとめ

要素のフォーカスは element.focus() が基本で、対象は getElementByIdquerySelector で取得します。

読み込み時は autofocusDOMContentLoaded、スクロールを抑えるなら preventScroll、フォーカスできない要素には tabindex、と状況に応じて使い分けましょう。最初のエラー項目へのフォーカスや、activeElement での状態取得まで押さえると、使いやすく親切なフォームが作れます。