HTML

The autofocus attribute automatically places the cursor in an input field as soon as the page loads, letting users start typing right away.

<input autofocus>

autofocus 属性とは

HTML の autofocus は、ページが読み込まれた直後(厳密には DOM が完全に構築され、描画キューが落ち着いた段階)でブラウザに “このコントロールへフォーカスを当てよ” と指示するシンプルなブール属性です。フォームで最初に入力してほしい箇所へカーソルを置く、といった ユーザーの手間を 1 クリックでも減らす 目的で導入されました。

ただし「フォーカスを奪う」という行為はアクセシビリティ・ユーザー体験・セキュリティの三面で影響が大きく、使い方次第では UX を悪化させる諸刃の剣となります。

特に、ページが読み込まれた直後にフォーカスを当てると、キーボード操作を行うユーザーにとっては便利ですが、マウス操作を行うユーザーには混乱を招く可能性があります。そのため、autofocus 属性は慎重に使用する必要があります。

最小構文と即効サンプル

HTML

<form action="/search" method="get">
	<input type="search" name="q" placeholder="Enter keywords" autofocus>
	<button>Search</button>
</form>

ブール属性なので autofocus="autofocus"autofocus="" と書いても同義。慣例的に短縮形を使います。

ページ内で 最初に見つかった 1 要素だけ が有効。複数指定しても最初のもの以外は無視されます。

disabled / hidden / display:none / visibility:hidden / inert などでフォーカス可能でない場合はスキップされ、次の候補も自動では選ばれません(結果として “どこにもフォーカスが当たらない” 状態になり得る点に注意)。

動作タイミングとブラウザ実装の豆知識

  1. DOM Ready → レンダーツリー構築完了 → Layout → Paint
  2. イベントループがアイドル状態になった瞬間、ブラウザは autofocus-able な要素を走査
  3. 条件を満たす最初の要素へ focus() イベントをディスパッチ

Early 2020 s の仕様変更で セキュリティ警戒レベルが高いコンテキスト(例:クロスオリジン iframe)では自動フォーカスが抑制 されるようになりました。

Chrome 102+ は バックフォワードキャッシュ復元時 にあらためて autofocus を適用します。一方 Safari は復元時には走査しないため挙動差に留意。

アクセシビリティ& UX ベストプラクティス

スクリーンリーダー利用者はフォーカス移動を “ページ読み上げ中に突然飛ばされる” と感じやすい。<h1> 見出し直後に配置し、文脈をつなぐナレーションがあると混乱を抑えられます。

モバイルではソフトキーボードが即座に現れ、レイアウトが大きく押し上がるため、ユーザーが “コンテンツを一瞥” できなくなる。重要度とページタイプ(検索専用 vs. 読み物)で使い分ける。

フォームが複数あるページでは、ユーザーが入力意図を持たないエリアで勝手にフォーカスを奪わない。“明確に主目的のフォーム only” が原則。

よくある「効かない」ケースと対処

SPA や Intersection Observer で非同期レンダリング されたコンポーネント
例)Vue/React でモーダルをポータルレンダー → 初回 display:none → 後から表示
対処: mounted / useEffectel.focus() を明示呼び出し。
Shadow DOM 内要素
autofocus 自体は有効だが、シャドウ境界を跨いでフォーカスリングが隠れると UX が悪化。
ブラウザのヒストリ復元
Chrome は OK、Safari/Firefox は無視 → 必要なら pageshow イベントで再フォーカス。

JavaScript での代替と補完

JavaScript

// Progressive Enhancement: まず HTML の autofocus を書き、
// 動的レンダリング時のみ JS で fallback
function safeFocus(el) {
	if (!el) return;
	requestAnimationFrame(() => {
		// 非表示判定を自前でチェック
		const rect = el.getBoundingClientRect();
		const visible = rect.height > 0 && rect.top >= 0 && rect.bottom <= window.innerHeight;
		if (visible) el.focus({ preventScroll: true });
	});
}

preventScroll:true で 即スクロールによる CLS (Cumulative Layout Shift) を回避。

複雑な UI では “初回ロード直後はスクロールさせず、ユーザー操作でスクロール時にだけフォーカス” という UX も選択肢。

セキュリティ的視点 ― フィッシング対策

autofocus は キーロガー系攻撃 で乱用されることがある(例:見えないパスワードフィールドへ自動フォーカス → 努力せずパスワードを盗む)。

ブラウザは “同一オリジン+ユーザーの信頼済みジェスチャ” かつ “フィールドが表示領域内” という条件でフォーカス制限を行うが 完全防御ではない。

CSP (Content Security Policy) の frame-ancestors を併用し、怪しい iframe 埋め込みをブロックするのが望ましい。

モダンフレームワーク連携 Tips

React

JavaScript

const SearchBox = () => {
	const ref = useRef(null);
	useEffect(() => {
		ref.current?.focus();
	}, []);
	return <input ref={ref} type="search" placeholder="Search…" />;
};

SSR(Next.js 等)で autofocus を書くと Hydration ミスマッチ が起こる場合があるため、クライアント側で useEffect へ寄せるのが安全。

Vue 3

HTML

<script setup>
import { onMounted, ref } from 'vue';
const el = ref();
onMounted(() => el.value?.focus());
</script>

<template>
	<input ref="el" placeholder="検索語…" />
</template>

Vue の <input autofocus> 自体は動作するが、遅延マウント時にはズレるのでディレクティブ化(v-focus)して制御粒度を上げると保守しやすい。

Angular

HTML

<input #box />

TypeScript

@ViewChild('box', { static: true }) box!: ElementRef<HTMLInputElement>;
ngAfterViewInit() { this.box.nativeElement.focus(); }

ルーター遷移で再描画される際、Resolver でデータ待ちする場合は ngAfterViewInit 内でタイマーを挿む とチラツキが軽減。

ブラウザ互換性メモ

デスクトップ
Chrome 4+, Firefox 4+, Safari 5+, Edge Legacy 12+ → ほぼ網羅
モバイル
iOS Safari・Android Chrome ともに早期からサポート
IE11
動作するが autofocus 時に scrollIntoView() 相当の挙動。古いレイアウトで “画面最下部へジャンプ” ケースがあるため、条件付きクラスで回避推奨。

テスト自動化の観点

E2E ツールでフォーカスを検証
Cypress
cy.focused().should('have.attr', 'name', 'q')
Playwright
await expect(page.locator('[name=q]')).toBeFocused();
ビジュアルリグレッション
フォーカスリングの有無が差分になりやすい。初回キャプチャ時点でフォーカス除去用の :focus-visible スタイルを整備しておくと false positive を減らせる。

上級者向け Q&A スナップショット

Q. ページ内に 2 つの autofocus が存在し、どちらも display:none だったら?
A. いずれもフォーカス不可 → どこにもフォーカスが当たらず、スクリーンリーダーは DOM 先頭から読み上げを続行。
Q. SPA で仮想ページ遷移時に “ブラウザアドレスは不変” だが autofocus を効かせたい。どう設計?
A. ライブラリ側のルーターイベント(例:Vue Router の afterEach)で “スクリーントップ/ダイアログ開閉” を検知し、対象ノードへ focus({preventScroll:true}):tabindex="-1" を一時付与し、キーボードタブ順を壊さない工夫を添えると自然。
Q. フォーカス移動による CLS をゼロにするには?
A. position:fixed のステルスプレースホルダーを読み込み直後に表示 → 実際の UI が描画されたら focus() → プレースホルダーを除去。視覚的なジャンプを 0 に近づけられる(ただし実装難度高)。

まとめ

autofocus は “1 クリック削減” の即効薬 だが、アクセス環境・ユーザー意図・セキュリティの三要素を考慮したうえで “ここぞ” に限って使用する。

SPA & モバイルが当たり前の 2025 年では、JavaScript 補完が実質標準。preventScroll・タイミング調整・ヒストリ復元時の再適用までワンセットでハンドリングすると、プロダクション品質に到達する。

テスト自動化でフォーカス検証をルーチン化 し、リグレッションの温床を潰すのが上級者のたしなみ。