iPhone Safariで入力エラーが起きた時に該当箇所へスクロールする

こんにちは、ナカムラです。
今回はフォームの機能で困ったことがあったので、備忘録として書きたいと思います。

HTML5のフォームバリデーションでは必須項目が未入力の場合や、入力形式が異なる場合にエラーメッセージを表示しユーザーへ伝える機能が備わっています。
Chrome、Edge、Firefox、Safariなどで機能しますが、iPhone実機で確認したところ、なぜかラジオボタンとチェックボックスがうまく機能しませんでした。
必須項目としてrequired属性をセットし、未選択のまま送信ボタンを押しても、画面が変わりません。
実はこれ、必須のバリデーションは機能しており、フォーカスはされています。
ラジオボタンとチェックボックスだけ「該当箇所へスクロールする」動作が実行されません。
このままでは困るので、JavaScriptで該当箇所へスクロールする処理を追加しました。

DEMO

See the Pen iPhone Safariで入力エラーが起きた時に該当箇所へスクロールする by Nakamura (@takayo-nakamura) on CodePen.

処理は単純でSafariで送信ボタンが押された後にフォーカスされたラジオボタンまたはチェックボックスを探し、もし存在するなら取得した要素の位置へスクロールするという処理になります。
※ちなみに、ラジオボタンやチェックボックスのrequiredは、name属性でグループ化されているため、一つ目だけに書けば良いです。

Safariかどうか判定する

userAgentを使って判定します。
※本当はiOSかどうかの判定も加えますが、複雑になるのでこの記事ではSafariのみの判定にしています。

const ua = window.navigator.userAgent.toLowerCase()
let safari
if (ua.indexOf('chrome') !== -1) {
  safari = false
} else if (ua.indexOf('safari') !== -1) {
  safari = true
}

if(safari){
}

送信ボタンが押された後というイベントを付与する

addEventListenerでイベントを付与します。
スマホなのでtouchendを使用します。

const btn = document.getElementById('submitBtn')
btn.addEventListener('touchend', () => {
})

フォーカスされたラジオボタンまたはチェックボックスを探す

const focusElm = document.querySelector('input[type="radio"]:focus,input[type="checkbox"]:focus')

フォーカスされたラジオボタンまたはチェックボックスの位置へスクロールする

スクロールは.scrollIntoView()を使うと簡単です。
※smoothはCSSでつけても良いですが、オプションの設定でも実装可能なので、今回はJavaScriptで対応しました。

if(focusElm){
      focusElm.scrollIntoView({
        behavior: 'smooth'
      })      
    }

最後に

これはブラウザ側で対応して欲しい問題なので、いつか改善されることを願います。

ユーザーエージェントの判定は複雑になるので、今回は昔ながらの書き方で説明しています。
実際に実装する場合は下記の記事などを参考にしてください。

ics.media

qiita.com