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

HTML, React

2019 年 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

試す

下記の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 属性は存在しない。
代わりに、従来からフォーカス可能だった要素が autoFocus prop を持つ Element として列挙され、autoFocus={true} が渡っていれば、mount 時に focus() を実行する。
要するに、先に述べたようなブラウザ差異に対しての Polyfill としても機能する。

autoFocus の要素に、autofocus 属性は付かない。
ただし、Hydrate する時は別で、autoFocus な要素にはしっかり autofocus 属性が付く。
これは hydrateInstance の挙動の問題と、 Server そして Client 両方で DOM の構造を保つための解決案だそう。
autoFocus doesn't work with SSR in React 16 · Issue #11159 · facebook/react

autofocusは良いのか

多くの場合は使わなくて済む。

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

良いことがない。
強いて言えば data:text/html, <html contenteditable 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

終わり

オチなし。