処理の進捗率を横棒グラフで視覚的に伝えるUIコンポーネント。ファイルアップロード・インストール・データ処理など進捗が計測できる処理に使われる。進捗が計測できない処理には「Indeterminate(不定)」バリアントを使う。Spinnerよりも「どれくらい時間がかかるか」をユーザーが予測できるため、長い処理での待機体験を改善する。
この記事を読むと、Spinnerとの使い分け・Determinateと Indeterminateの使い分け・フェイクプログレスを避けるべき理由・role="progressbar" と aria-valuenow の実装が自分でできるようになります。
1. UI例(Preview / Live)
実装で見る(GunjoUI)
この部品を、デザインシステム GUNJO の実装で確かめられます。
2. 定義(Definition)
処理の進捗率を横棒グラフで視覚的に伝えるUIコンポーネント。2つのバリアントがある:
- Determinate(確定):進捗率(0〜100%)が計測できる場合。
aria-valuenowを動的に更新する - Indeterminate(不定):進捗率が計測できない場合。バー全体がアニメーションして「処理が動いている」ことだけを伝える
Spinner vs Progress Bar の選択基準:進捗が数値で計測できるかどうかが唯一の判断基準。計測できない = Spinner / Indeterminate Progress Bar、計測できる = Determinate Progress Bar。
3. 使い分け(When to use / When NOT to use)
3.1 When to use
- ファイルアップロード / ダウンロード(進捗率が計測できる)
- インストール / パッケージ処理
- 複数ステップの処理(ステップ付きProgress Bar)
- フォームの記入完了度(任意だが進捗の可視化として)
3.2 When NOT to use
- 進捗が計測できない処理(API呼び出し・AI処理など)→ Indeterminate または Spinner を使う
- 数秒以内の短い処理 → Spinner で十分
- 偽の進捗(フェイクプログレス)を見せたい場合 → 使わない(Indeterminateを使う)
4. 設計判断の核(Decision Principles)
Progress Barの核は「正直な進捗表示」——フェイクプログレスは短期的にユーザーの不安を和らげるが、長期的に信頼を損なう。進捗が計測できないならIndeterminateを使う。
- フェイクプログレスを実装しない:
0% → 30%(実際の進捗なし)→ 100%のような偽の進捗は、ユーザーが気づいた時の信頼損失が大きい。進捗が計測できないならIndeterminateバリアントを使う aria-valuenowをリアルタイムで更新する:aria-valuenow={progress}は React の state 更新と連動して自動的に更新される。静的なaria-valuenow="0"のままではスクリーンリーダーが常に0%と読み上げる- 完了後は必ずフィードバックを提供する:Progress Barが100%になった後、Toastや完了メッセージで「処理が完了した」ことを明示的に伝える
5. 状態設計(States)
| 状態 | aria-valuenow | 視覚的な表示 |
|---|---|---|
| Idle | — | 非表示 |
| Running(Determinate) | 0〜99 | バーが伸びる |
| Running(Indeterminate) | 設定なし | バーが往復アニメーション |
| Complete | 100 | 100%表示 → Toast/Alert |
| Error | — | Progress Barを赤色に変えるか非表示 |
6. バリエーション設計(Variants)
| バリアント | 進捗計測 | 使用例 |
|---|---|---|
| Determinate | ✅ | ファイルアップロード・ダウンロード |
| Indeterminate | ✗ | API処理・AI生成・進捗不明の処理 |
| ステップ付き | ✅ | 複数フェーズの処理・ウィザード |
| カラー付き | ✅ | 使用量(警告/危険閾値で色変化) |
7. パターン集(Good / Bad / How to fix)
7.1 Bad(典型3つ)
- 進捗が計測できないAPI呼び出しに
0→30→止まる→突然100のフェイクプログレスを実装する <div class="progress-bar" style="width: 45%" />にroleもariaもなく、スクリーンリーダーが進捗を把握できない- Progress Barが100%になっても何の通知もなく、ユーザーが処理完了に気づかない
7.2 Good(対になる3つ)
- 進捗が計測できない処理にはIndeterminateバリアントを使い、完了はToastで通知する
role="progressbar" aria-valuenow={progress} aria-valuemin={0} aria-valuemax={100}を付与してリアルタイムで更新する- 100%到達後
setTimeout(500ms)でProgress Barを非表示にして、Toast/Alertで「アップロード完了」を通知する
7.3 How to fix(手順)
- 進捗が計測できるか確認する → できない場合はIndeterminate CSSアニメーションに変更する
role="progressbar"+aria-valuenow+aria-valuemin+aria-valuemax+aria-labelを付与する- 完了処理(100%到達後)に Toast / Alert で完了通知を実装する
8. ルール(Must / Better)
Must(守らないと壊れる)
Better(品質が跳ねる)
9. アクセシビリティ要件(必須)
Screen Reader
<!-- Determinate -->
<div
role="progressbar"
aria-valuenow="67"
aria-valuemin="0"
aria-valuemax="100"
aria-label="ファイルアップロード進捗"
>
<!-- 視覚的なバー -->
</div>
<!-- Indeterminate(aria-valuenowなし) -->
<div
role="progressbar"
aria-label="処理中"
aria-busy="true"
>
</div>
10. 実装メモ(Implementation Notes)
- shadcn/ui の
Progressコンポーネントは@radix-ui/react-progressベースでrole="progressbar"とaria-valuenowの更新が自動処理される - Indeterminate の CSS アニメーションは
@keyframesでtranslateX(-100%) → translateX(350%)のように実装する。Tailwind にはIndeterminate用プリセットがないためカスタム@keyframesが必要 - ファイルアップロードの進捗は
XMLHttpRequest.upload.onprogressまたはfetch+ReadableStreamで取得できる。axiosではonUploadProgressコールバックが利用できる
11. 関連リンク
- 関連するUIデザイン原則: フィードバック (Feedback), 状態の可視化 (Visibility of System Status)
- 用語集(定義): アクセシビリティ (Accessibility)
- 関連するUIコンポーネント(横): Loading(ローディング), Spinner(スピナー), Status Bar(ステータスバー)
12. まとめ
Progress Barの設計で最重要なのは「正直な進捗表示」と「aria-valuenow のリアルタイム更新」です。進捗が計測できない処理にはIndeterminateバリアントを使い、フェイクプログレスは避けてください。完了後は必ずToast/Alertで通知することで、ユーザーが処理完了を確実に認識できます。