autofocusがグローバル属性になったのでなんか書く

今年の8月末、HTML LSで、autofocus属性がグローバル属性となりました。
ブラウザの対応が進めば、全ての要素でautofocusを使用することができます。

autofocus属性とは

autofocus属性は、ページの読み込み時に自動的にフォーカスする要素を指定するものです。

これまでautofocusは、button, inputなど、フォーカス可能な要素でしか使用できませんでした。
一方で、全ての要素は、tabindexまたはcontenteditable属性を追加することでフォーカスが可能となっています。

したがって、autofocusは全てのHTML要素で使用できるべき、という内容のIssueが4月に上がってました。
Move autofocus content attribute to HTMLElement · Issue #4563 · whatwg/html

そして、それに関するPRが今年の8月末にmergeされ、autofocusはグローバルとなりました。
Make 'autofocus' a global attribute by tkent-google · Pull Request #4830 · whatwg/html

現在、autofocus属性はHTMLOrSVGElementに含まれています。(SVGでautofocus、とは…)
HTML LSの例では、contenteditable属性のあるdiv要素にautofocusを適用しています。
HTML LS The autofocus attribute

試す

Chromeの場合、この仕様は79以降で対応する予定です。
Canaryでは既に対応しているので、試してみます。
https://www.chromestatus.com/feature/5654905853313024

下記のHTMLは、div要素とinput要素の両方にautofocus属性が付与されています。
そして、div要素はフォーカス可能です。

html
<div autofocus contenteditable>hoge</div>
<input autofocus type="text" />

これまでは、div要素のautofocusは無視され、input要素にフォーカスされました。

input要素の前にautofocusを付けたdivが存在するが、フォーカスされるのはinput要素

しかし、これからはdiv要素の方にフォーカスされるようになります。

新しい仕様では、div要素の方にフォーカスされる

要素生成時のautofocus

ここからは小ネタです。

autofocus属性のついた要素は、基本的にページを読み込んだ時にフォーカスされます。
ただし、動的に生成される場合のブラウザの挙動は、それぞれ異なるものになっています。

例えばChromeでは、「ページ読みこみ後にユーザーが他の要素にフォーカスしていない」「他にautofocusを持つ要素が生成されていない」状態でautofocus属性のついた要素が動的に生成される場合、自動的にフォーカスする挙動をとります。
Firefoxは、動的に生成されたautofocus付きの要素にはフォーカスをしません。
Safariは独特で、ページロード時にも生成時にもフォーカスします。

autofocusではありませんが、dialog要素のフォーカス挙動もそれぞれ異なっています。
例えばshowModal()した時、Chromeではautofocusの有無に関わらず、dialog内のinputにフォーカスします。
つまり、内部的にautofocusのような振る舞いをしています。(この辺の実装は1文字も読んでません、憶測です)
それにつられてFirefoxで試しても、autofocusがあろうがなかろうが、showModal()を通してinputにフォーカスすることはありません。

このように、autofocusのタイミングは何もかも違うので、ブラウザ間の差異を埋めるのは難しいです。

ReactのautoFocus

一方、Reactにautofocus属性は存在しません。
代わりにautoFocuspropを持てるDOM Elementが列挙されていて、これらの要素にautoFocus={true}が渡っていれば、mount時にfocus()を実行します。
要するに、先に述べたようなブラウザ差異に対してのPolyfillとしても機能します。

autoFocusの要素に、autofocus属性は付きません。
ただし、Hydrateする時は別で、autoFocusな要素にはしっかりautofocus属性が付いています。
これはhydrateInstanceの挙動の問題+ServerとClient両方でDOMの構造を保つための解決案のようです。
SSRでのautoFocusを巡る議論やPRは、以下で確認できます。
autoFocus doesn't work with SSR in React 16 · Issue #11159 · facebook/react

autofocusは良いのか

多くの場合は使わなくて済むものだと思います。

  • ブラウザによって挙動がばらばら
  • 直接飛ぶので、スクリーンリーダーに適切なラベルを与えられない可能性がある
  • モバイルなどでフォーカスした時、キーボードが出て煩わしいことがある
  • ページ読み込み直後に、ショートカットキーでの操作を阻害する恐れがある
  • 本当にフォーカス制御してほしい対話型なケースでうまく機能しない

良いことがありません。

autofocusの使用に関するガイドラインはありませんが、WCAGの達成基準で言えば、「予測可能」の3.2.2が近いものだと思います。
ユーザーの意識なくコンテキストを変更すると、ユーザーが混乱する、と言うものです。
ユーザーからのアクションに応じて、コンテンツを切り替える分には問題ありません。
となると(基本的に)ページの読み込み時にしか行われないautofocusの使用が、問題を孕んでいるように思えます。

ユースケースとして多いのが、入力フォームへのジャンプでしょうか。
ユーザーがこれからフォームに移ることを予測できて、かつ入力事項や注意事項を完全に理解し、ショートカットキーを使わず、いつでもどこでもPCを持ち歩いているような人でないと不便なので、いらないのだと思います。

ReactのautoFocusは、mount時のfocus()をサポートするので、対話的なコンテンツなどで使いどころがありそうです。
ただ、eslint-plugin-jsx-a11yには、autoFocusの使用を禁止するruleがあります。
no-autofocus.md at master · evcohen/eslint-plugin-jsx-a11y

終わり

オチはないです