本文へスキップ

エラー状態

読み込み失敗をその場で伝えるエラーパネル。「再試行」を押すと一瞬スピナーが回り、成功状態へ切り替わる。

プレビュー

クリック

操作クリック/タップで動きます。

使いどころ

通信エラー・API失敗・タイムアウトなど、その場でやり直せる失敗を伝える場面に向く。画面全体を差し替えるのではなく、失敗した領域だけをこのパネルに置き換えることで、ユーザーはどこが失敗したのか正確に把握でき、再試行ボタンで同じ操作を繰り返せる。逆に、認証切れで別ページへの遷移が必要な場合や、入力バリデーションのようにユーザー側の入力ミスが原因の場合には向かない。前者はログインページへの誘導、後者はフォームのインライン検証メッセージの方が適切になる。1画面に複数のデータ取得が独立している場合(ウィジェットが並ぶダッシュボードなど)は、失敗した部分だけをこのパネルに差し替え、他のウィジェットは正常表示のまま残すのが基本方針になる。

仕組み

failure/loading/successの3状態をerr-btn要素へのクラス付け外し(is-loading・is-ok)で切り替える単純な状態機械になっている。クリックするとまずis-loadingを付けてボタンを無効化し、setTimeoutで通信を疑似的に1.3秒待った後、is-okへ切り替えてアイコン・メッセージ・サブテキストをすべてinnerHTMLで書き換える。成功表示は2.6秒後に自動でresetPanelへ戻るが、これはデモ用の挙動で、実際のアプリでは成功後はパネルごと本来のコンテンツへ置き換えるのが普通なので、自動リセットのタイマーはそのまま持ち込まないこと。スピナーはborder-top-colorだけ変えたCSSアニメーションで、DOM要素自体は最初から存在し、is-loadingクラスの有無で表示・非表示を切り替えている。

実装の注意

実装をコピーする際に見落としやすいのが、resetTimerがグローバル変数扱いで複数のエラーパネルを1ページに置くと状態が競合すること。パネルごとにタイマーとDOM参照をカプセル化する必要がある。また再試行中にボタンを無効化しているが、ネットワークが実際に不安定な状況では1.3秒のタイムアウトでは短すぎることがあり、本番実装ではfetchの実際の完了を待つPromiseベースの制御に置き換える必要がある。さらにこのデモは常に成功で終わる作りになっているため、実際には失敗が続くケースの表示(「何度も失敗する場合はサポートへ」のような案内や連絡先リンク)も併せて用意しておくと、ユーザーが手詰まりにならずに済む。

アクセシビリティ

パネル全体にrole="alert"とaria-live="assertive"を最初から付けてあり、これは中身が動的に変化するたびにスクリーンリーダーへ即座に割り込んで読み上げさせる指定になる。エラー発生時に強く知らせたい場面では有効だが、再試行中や成功時のような緊急度の低い変化にまでassertiveで割り込むと、ユーザーの読み上げ操作を頻繁に中断してしまう。実装するときは、初回のエラー表示だけassertive、再試行中・成功などの穏やかな変化はaria-live="polite"の別領域に分けるなど、緊急度に応じてlive領域を使い分けるとよい。ボタンのラベル文言(再試行→再試行中…→読み込めました)はbutton内のテキストノードとして変わるため、フォーカスが当たったままの操作でも変化が読み上げに乗る。

調整して使う

調整しやすいのは3点。まず自動リセットの有無と間隔(既定2.6秒)で、実運用では自動で消さずユーザーの次の操作まで表示し続ける設計に変えることが多い。次にアイコンとメッセージの組み合わせで、通信エラー・権限エラー・サーバーエラーなど原因別にアイコン(三角の警告・鍵マーク・雲に斜線など)とメッセージを出し分けると、ユーザーが取るべき行動を判断しやすくなる。最後に再試行の上限で、このデモは何度でも再試行できるが、実際には3回失敗したら再試行ボタンをサポート連絡導線に差し替えるなど、失敗が続く場合のエスカレーションを用意すると親切になる。パネルの置き場所もページ全体を覆うか一部だけ差し替えるかで印象が変わる。

コード(コピーして使えます)

<div class="stage" id="stage">
  <div class="err" id="errPanel" role="alert" aria-live="assertive">
    <div class="err-icon" id="errIcon" aria-hidden="true">
      <svg width="26" height="26" viewBox="0 0 24 24" fill="none">
        <path d="M12 3L1.5 21h21L12 3Z" stroke="#c0492f" stroke-width="2" stroke-linejoin="round"/>
        <line x1="12" y1="10" x2="12" y2="14.5" stroke="#c0492f" stroke-width="2" stroke-linecap="round"/>
        <circle cx="12" cy="17.6" r="1.1" fill="#c0492f"/>
      </svg>
    </div>
    <p class="err-msg" id="errMsg">読み込みに失敗しました</p>
    <p class="err-sub" id="errSub">通信環境をご確認のうえ、もう一度お試しください。</p>
    <button class="err-btn" id="retryBtn">
      <span class="err-spinner" id="errSpinner" aria-hidden="true"></span>
      <span class="err-label" id="errLabel">再試行</span>
    </button>
  </div>
</div>

タグ

同じカテゴリ「エラー・システム状態」のほかのパーツ

関連パーツ