---
title: a11y/no-autofocus · ダイアログ外の autofocus
description: autofocus はページ読み込み時にユーザーの意図と無関係にフォーカスを移動させます。スクリーンリーダーのユーザーは組み立てていたページの文脈を失い、キーボードのユーザーはページの途中に放り出されます。
---

**重大度:** warning · **カテゴリ:** a11y

## チェック内容

リテラルな `autofocus` 属性（素の属性または文字列値）を持つ要素を検出します。ただしその要素が `<dialog>` 自身であるか、同じコンポーネントテンプレート内で `<dialog>` または popover コンテナの中にある場合は除きます。

```svelte
<input autofocus placeholder="Search" />
```

検出しないもの:

- 式による `autofocus={expr}`。式は `false` になりえるため、描画される属性は静的に判定できません。
- `<dialog>` 要素自身、またはその子孫の `autofocus`。ダイアログのフォーカス処理はページ読み込み時ではなく表示時に走り、`autofocus` を持つ子孫を尊重します。これがこの属性の正しい使い方です。
- `popover` 属性を持つ要素の子孫。形式(素・リテラル・式)を問いません。popover のフォーカス処理はダイアログと同様に振る舞い、式は実際の popover 値に解決されうるため、正規のパターンを検出してしまうよりも除外を寛大に保ちます。
- スプレッド属性経由で供給される `autofocus`。静的解析の範囲外です。

## なぜ重要か

`autofocus` はページ読み込み時に、ユーザーの意図と無関係に、ターゲットより前のすべてを飛ばしてフォーカスを移動させます。スクリーンリーダーのユーザーは組み立てていたページの文脈、つまり最初に聞くはずだったタイトル・見出し・ランドマークを失い、キーボードのユーザーは何が前にあったのか分からないままページの途中に放り出されます。`<dialog>` や popover の中では意味が異なります: フォーカスはコンテナの表示時に移動し、それはまさに WAI-ARIA のダイアログパターンが要求するものです。それ以外の場所では、ほぼ確実にユーザビリティのバグです。

## 修正方法

属性を削除し、フォーカスはページ先頭から始めさせます。

```svelte
<input placeholder="Search" />
```

コントロールがダイアログや popover に属するなら、そのコンテナの中に移動して `autofocus` を残してください。それがサポートされたパターンです。ユーザー操作に応じたフォーカス移動はイベントハンドラで行います。

## 制限事項

dialog/popover の除外が見えるのは同じコンポーネントテンプレート内の祖先だけで、祖先チェーンはレンダリング位置が字句的でないすべての構造（コンポーネント境界、`{#snippet}` 本体、`<svelte:element>`、カスタム要素や未知のタグ、`{@html}`、`{@render}`、`<slot>`）で途切れます。途切れた先ではダイアログを証明できないため、親が `<dialog>` の中にレンダリングするコンポーネント内の `autofocus` は既知の偽陽性です。その要素を `<!-- svelte-vitals-disable-next-line a11y/no-autofocus -->` で黙らせてください。

## Svelte コンパイラとの重複

コンパイラは同様のマークアップに `a11y_autofocus` を警告し、同じ `<dialog>` の除外を持ちます。この重複は意図的です: コンパイラの警告はビルドログに流れるだけで、スコアもゲートも抑制もしません。一方このルールはヘルススコアに反映され、`svelte-vitals-disable-next-line` を尊重し、`--fail-on` で CI を失敗させられます。

意図的な相違点が4つあります。

- 式による `autofocus={expr}` はコンパイラが警告しますがこのルールは沈黙します。式は `false` になりえます。
- `<dialog>` の深い子孫(例: `<dialog><div><input autofocus /></div></dialog>`)はコンパイラが警告しますが、これは直近の要素祖先しか確認しないためです。このルールはチェーン全体を辿って正しく通します。
- `<svelte:element>` を挟んだ祖先はコンパイラが沈黙し、このルールは途切れたチェーンとして報告します: 包含関係が判定できないときのデフォルトが逆です。
- popover コンテナはこのルールでは属性を除外しますが、コンパイラでは除外しません。

## モードによる違い

ありません。このルールが読むのは同じ `.svelte` / `.ts` のソースファイルなので、CLI、Vite プラグインのビルド、ライブダッシュボードの静的ベースラインのいずれでも結果は同一で、レンダリング済み HTML の解析で再評価されることもありません。`--route` で実行範囲を絞ると、このルールは動きません。コンポーネントスコープのルールには、検出を紐づけるルートが無いためです。

## 無効化

ページ読み込み時の `autofocus` が本当に意図したものなら(検索専用ページ、ログインフォームなど)、`<!-- svelte-vitals-disable-next-line a11y/no-autofocus -->` で個別の要素を黙らせるか、ルールを無効化します。

```js svelte-vitals.config.js
export default {
  rules: {
    'a11y/no-autofocus': 'off'
  }
};
```
