ステップフォーム
3ステップ(基本情報→住所→確認)を進捗バー付きで切り替え。次へ/戻るボタンと必須チェックを備え、最後に入力内容を確認表示する。
プレビュー
操作実際に入力して試せます。
使いどころ
入力項目が意味のあるまとまりに分かれ、進捗を見せることに価値がある長めのフォーム(会員登録、予約手続きなど)に向く。この実装は基本情報→住所→確認の3ステップで、ドットと接続線・見出しテキストの3つで「今どこにいるか」を示す。項目数が少ない(2〜3項目程度の)フォームにはオーバースペックで、1画面にまとめた方が速い。またこの実装は前へ/次への一方向遷移のみで、進捗ドットをクリックして任意のステップへ直接ジャンプすることはできない。リロードやタブを閉じると入力内容は失われる(localStorageなど永続化する仕組みが無く、値は各inputのDOM状態そのものが唯一の保持場所である)ため、長時間かかる可能性のある申込フォームでは離脱リスクを別途考慮する必要がある。
仕組み
3つのパネルはすべてhidden属性で切り替えられ、DOMからは削除されない。goTo(s)が現在のパネルをhiddenにし、新しいステップのパネルを表示し、ドットの.active/.doneクラスと接続線の.doneクラス、見出しテキストを一括で更新する。ステップ2(確認画面)に来たときだけ showConfirm() が呼ばれ、これは各inputのvalueを都度DOMから直接読み取ってdl要素に書き出す。フォーム値を保持する専用のJSオブジェクトは存在せず、DOM上のinput自体が唯一の状態源になっているため、戻るボタンで前のステップに戻って値を書き換えても、確認画面に再度進めば必ず最新の値が反映される。検証はvalidate(s)がそのステップに属するinputのvalue.trim()が空でないかだけを見ており、形式までは見ていない。
実装の注意
validate()は「空でないか」しか見ないため、メールアドレス欄に「abc」とだけ入力しても次のステップへ進めてしまう。形式チェックまで含めるなら、リアルタイム検証の実装のようにフィールドごとのルールを別途持たせる必要がある。次に、goTo()はパネルの表示切り替えとテキスト更新は行うが、フォーカスの移動は一切していない。マウス操作なら見た目の切り替わりに気づけるが、キーボードユーザーやスクリーンリーダー利用者は次のステップへ進んだ後もフォーカスがどこにあるか変わらないため、ステップが変わったことに気づきにくい。新しいパネルの最初の入力欄か見出しへ明示的にfocus()を移すべきである。また [0,1,2]の配列、fieldsマップ、stepTitles配列など、ステップ数と要素IDがコード内の複数箇所にハードコードされているため、ステップを4つに増やす場合はこれらすべてを漏れなく更新する必要があり、1箇所でも直し忘れるとその分だけ挙動がずれる。
アクセシビリティ
必須項目はラベル内の赤いアスタリスク(span.ms-req)で視覚的にのみ示されており、input要素自体にはrequiredもaria-requiredも付いていない。スクリーンリーダー利用者は視覚的な「*」を確認できないため、その項目が必須であることを知る手段がない。requiredまたはaria-required="true"を各inputに追加すべきである。エラーメッセージ #ms-err はhidden属性の切り替えだけで表示され、aria-liveが無いため、検証に失敗して足止めされたことがスクリーンリーダー利用者に自動的には伝わらない。ブロッキングなエラーなのでaria-live="assertive"が適切である。進捗表示についても、ドット自体には個別にaria-label(「ステップ1」等)が付いているが、コンテナのaria-label="進捗"だけでは今何ステップ目にいるかまでは伝わらず、実質的にはステップ見出しテキスト(#ms-step-label)の内容がユーザーへの主な伝達手段になっているため、これをaria-liveで囲んでステップ切り替え時に読み上げさせる対応が望ましい。
調整して使う
現状は一方向の逐次遷移だが、完了済みステップのドットをクリックして直接戻れるようにする(未来のステップへは先送りできないよう、validate済みのステップだけ許可する)拡張は使い勝手が上がる。郵便番号から住所を自動補完するような非同期検証をステップの検証に組み込むなら、次へボタンを検証完了までdisabledにする状態を追加する必要がある。ステップ数や項目数が増えて確認画面のDOM直読みが煩雑になる場合は、各フィールドの値を専用の状態オブジェクトに集約してから確認画面を描画する構成に切り替えた方が保守しやすい。長時間離脱の可能性がある申込では、ステップ移動のたびにlocalStorageへ下書き保存する変更が有効である。
コード(コピーして使えます)
<div class="ms-wrap">
<div class="ms-progress" aria-label="進捗">
<div class="ms-step-dot active" id="ms-dot-0" aria-label="ステップ1">1</div>
<div class="ms-line" id="ms-line-0"></div>
<div class="ms-step-dot" id="ms-dot-1" aria-label="ステップ2">2</div>
<div class="ms-line" id="ms-line-1"></div>
<div class="ms-step-dot" id="ms-dot-2" aria-label="ステップ3">3</div>
</div>
<div class="ms-step-label" id="ms-step-label">ステップ 1 / 3:基本情報</div>
<div class="ms-panel" id="ms-panel-0">
<div class="ms-field">
<label class="ms-label" for="ms-name">お名前 <span class="ms-req">*</span></label>
<input id="ms-name" class="ms-input" type="text" placeholder="山田 太郎" />
</div>
<div class="ms-field">
<label class="ms-label" for="ms-email">メール <span class="ms-req">*</span></label>
<input id="ms-email" class="ms-input" type="email" placeholder="taro@example.com" />
</div>
</div>
<div class="ms-panel" id="ms-panel-1" hidden>
<div class="ms-field">
<label class="ms-label" for="ms-zip">郵便番号 <span class="ms-req">*</span></label>
<input id="ms-zip" class="ms-input" type="text" placeholder="123-4567" inputmode="numeric" />
</div>
<div class="ms-field">
<label class="ms-label" for="ms-addr">住所 <span class="ms-req">*</span></label>
<input id="ms-addr" class="ms-input" type="text" placeholder="東京都渋谷区…" />
</div>
</div>
<div class="ms-panel" id="ms-panel-2" hidden>
<p class="ms-confirm-title">入力内容の確認</p>
<dl class="ms-confirm" id="ms-confirm"></dl>
</div>
<p class="ms-err" id="ms-err" hidden>必須項目を入力してください</p>
<div class="ms-actions">
<button class="ms-btn ms-back" id="ms-back" type="button" hidden>戻る</button>
<button class="ms-btn ms-next" id="ms-next" type="button">次へ</button>
</div>
</div>