Closed8

ブラウザーのオートコンプリートを自サイト内でデフォルトで無効化したい

akuaku

普通に <input /> と書いただけでは要素にフォーカスを合わせた時にブラウザー独自のオートコンプリート(自動補完)の候補が表示される[1]

既定では、ウェブサイト上の <input> 欄を通じてユーザーが送信した情報はブラウザーによって記憶されます。これよってブラウザーは、自動補完 (入力を受けた入力欄の補完候補をユーザーに提示する機能) や、オートフィル (読み込まれた入力欄をあらかじめブラウザーが補完する機能) を実現しています。
https://developer.mozilla.org/ja/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion

自分のブラウザー環境では表示されたことがないので関心が無かったが、社内でフィードバックを受けて気がついた。

脚注
  1. FireFoxではフォーカスを合わせた後に更にもう一度要素をクリックする必要がある ↩︎

akuaku

Chrome では 「設定→自動入力→住所やその他の情報→住所の保存と入力( chrome://settings/addresses )」が ON になっているとオートコンプリートが表示されるようになる。

「住所の」となっているが、 <input type="text" /> など住所以外の補完にも影響しているみたい。

なぜ自分の環境ではオートコンプリートが表示されなかったかというと、1Passwordの拡張機能が無効化していたらしい。(やはり動作確認はクリーンなブラウザーで行った方が良いな…)

akuaku

個別に無効化するには autocomplete 属性を off にすれば良い。
https://developer.mozilla.org/ja/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion#自動補完の無効化

autocomplete 属性は input textarea select 要素に指定することができるようなので完全に無効化したい場合はそれら全てに付けた方が良い。

入力値としてテキストまたは数値を取る <input> 要素、 <textarea> 要素、 <select> 要素、 <form> 要素で利用できます。
https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/autocomplete

form 要素にも指定することができて、この場合はその子孫の input textarea select に一括で反映できる。

<input>, <select>, <textarea> 要素に autocomplete 属性がない場合、ブラウザーはその要素のフォームオーナー、つまりその要素を子孫に持つ <form> 要素、または <form> 要素で id がその要素の form 属性で指定されているものの autocomplete 属性の値を使用します。
https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/autocomplete

akuaku

今開発しているサービスでは下記の理由からサービス内のほとんどの入力欄でオートコンプリートが不要である。

  • 過去の履歴から同じ内容を入力したいような input がほとんどない
  • あったとしてもブラウザーによって見た目も挙動も異なるオートコンプリートには頼りたくない
    • サイトのデザインに合わせて自前で実装したオートコンプリートを表示するようにしたい

そのためサービス内の全ての input でオートコンプリートを無効化し、必要な要素にだけ autocomplete 属性を明示的に指定することで有効化したい。

akuaku

Atomic Design の atoms に相当するようなベースコンポーネントがある場合は、そこに autocomplete="off" をデフォルトとして設定しておけば解決するような問題だが、今のプロダクトは Chakra UI を使用しているため、ベースコンポーネントの改変は難しい。

form 要素に autocomplete="off" を設定することである程度一括して反映可能だが、下記の理由からやめた。

  • form に囲まれていない input もあるので全てに適用できるわけでもない[1]
  • しっかりとルール化しておかないと自分以外のものが実装した時に指定漏れが生まれそう[2]
脚注
  1. もしかしたらオートコンプリートは form に囲まれている要素にしか表示されないかも知れないが… ↩︎

  2. ESLintでカスタムルールを作成して防ぐこともできそうではある ↩︎

akuaku

自分以外の開発者が実装する時にも autocomplete="off" について一切考慮しなくて良いように、次のアプローチを取ることにした。

  • querySelectorAllinput select textarea 要素を探索する
  • 見つかった要素に autocomplete 属性が指定されていない場合はデフォルト値として autocomplete="off" を設定する
  • これだけでは CSR で動的に追加された要素には対応できない場合がある。そのため MutationObserver を用いて子孫要素に更新があったら探索と設定を再度実行する

これらの処理を行うコンポーネントまたは hooks を作り、サービスのエントリーポイント [1]から呼び出す。

脚注
  1. Next.jsなら _app.tsx、その他なら App.tsx など ↩︎

akuaku

MutationObserver の発火頻度や querySelectorAll のパフォーマンス影響を危惧していたが、今のページ規模だと全く問題なかった。

時間がある時に動作デモを作る

akuaku

この注意書きを見るにオートコンプリートは form で囲まれた要素にしか現れなさそう。

メモ: 自動補完を提供するために、ユーザーエージェントは <input>/<select>/<textarea> 要素に次のことを要求することがあります。

name や id 属性を持つこと
<form> 要素の子孫であること
フォームが submit ボタンを持つこと
https://developer.mozilla.org/ja/docs/Web/HTML/Attributes/autocomplete

ブラウザーの挙動によると思うので主要ブラウザーで確認した上で、全ての form 要素に autocomplete="off" を付けておけばサービス内からブラウザーの autocomplete は撲滅できそう。

サービス内の form は既に10個を超えているからやはり先ほど書いた自動適用アプローチは使いたいかも。

このスクラップは5ヶ月前にクローズされました