Progress and status indicators
1) Principles
1. Instant response (≤ 100 ms). Any action is immediately confirmed visually: pressing the 'busy '/skeleton/microanimation →.
2. Honesty and predictability. Percentages reflect real progress, not "eternal 99%." If evaluation is not possible, use an indeterminate variant and explanation.
3. Context next to the activity. The indicator is where the user is looking/acting (button, card, block), not in the far corner.
4. Stealth after success. Success is a short check/fade and that's it. Error - understandable explanation and safe repetition.
5. Default availability. 'role = "progressbar"', 'aria-valuenow', live regions, contrast ≥ AA.
2) Types of indicators and when to use them
Linear progress (determine/indeterminate). Loading/importing/exporting, steps with clear scope.
Circular progress (usually indeterminate). Short local operations in compact places.
Stepper (step-by-step). Sequential steps ("Step 2 of 4"), KYC, master processes.
Skeleton (skeleton plugs). To substitute the content structure instead of spinners; avoid "shimmer" for users with 'prefers-reduced-motion'.
Status badges (success/warning/danger/info). The state of the object (In Process, Rejected, Ready).
Banner/status toast. Global events: offline, server failure, queue synchronization.
Inline loader (button/line). Local operations: "Save...," "Send...."
3) Definite vs uncertain progress
Determine: the amount of work is known → we show %/stages.
Indeterminate: unknown volume → "Processing in progress..." + context ("Usually up to 1-2 minutes").
State transition - You can start with indeterminate → go to determine when the evaluation appears.
ETA carefully: show the range ("~ 30-60 seconds") and avoid "promises."
4) Placement and patterns
Locally to action: 'aria-busy' button, spinner in table row, card progress.
Above the block/list: linear bar below the section header during batch operations.
Global: top subtle progress (route-change), system banners.
Sticky panel (mobile) : confirmation/progress on CTA in the lower dock.
5) Availability (A11y)
Progress:html
<div role = "progressbar" aria-valuemin =" 0" aria-valuemax =" 100" aria-valuenow =" 42" aria-label = "Load Report "> </div>
Indeterminate: set 'role = "progressbar"' without 'aria-valuenow', add explanatory text to 'role = "status"'.
Live regions: 'aria-live = "polite"' for regular updates, 'assertive' for critical ones only.
'aria-busy = "true" 'on a container that is temporarily blocked by actions.
Focus does not "jump": when changing the stage, move the focus to the stepper step header.
6) Copywriting and visual semantics
Briefly and in the case: "Loading in progress...," "Processing payment...."
Add "what's next": "Done. Let's refresh the page automatically.
Colors: green - success, orange - warning/attention, red - error. Color ≠ the only medium of meaning: give an icon/text.
7) Upbeat updates and pullbacks
Optimistic: we change the UI immediately (for example, the "Favorites" mark) and quietly confirm it with the server.
In case of error - soft rollback + explanation and'Retry '.
Critical operations (rate/payment): optionally "soft optimistic" (fix "Sent → Waiting for confirmation..."), but without changing the monetary condition before confirmation.
8) Queues and background tasks
Show the queue: 'n' tasks in processing, individual cards with progress.
Pause/cancel for long operations if possible.
Background processing: "In the background" badge, toast upon completion, "Task history" section.
9) Performance and timings
First reaction ≤ 100ms: use skeleton/inline-busy instead of void.
Animations: 120-180 ms (in), 80-140 ms (out), only 'transform/opacity'.
Long processes: updating progress no more than 10-15 times/sec; Group changes.
10) Snippets
Local progress at the button
html
<button id="export" class="btn" aria-busy="false">Экспорт CSV</button>
<script>
const btn = document. getElementById('export');
btn. addEventListener('click', async () => {
btn. setAttribute('aria-busy','true'); btn. disabled = true;
try {
const r = await fetch('/api/export', { method:'POST' });
if(!r.ok) throw new Error();
//show toast "Export has begun. We will notify upon readiness"
} catch {
//toast with cause and Retry
} finally {
btn. disabled = false; btn. setAttribute('aria-busy','false');
}
});
</script>
Linear determine
html
<div class="progress">
<div class="bar" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"></div>
</div>
<style>
.progress{height:4px; background:var(--bg-muted); border-radius:999px; overflow:hidden}
.progress. bar{height:100%;width:0%;background:var(--accent); transition:width. 16s}
</style>
<script>
const bar = document. querySelector('.progress. bar');
let n=0; const t=setInterval(()=>{ n=Math. min(100, n+5); bar. style. width=n+'%'; bar. setAttribute('aria-valuenow',n); if(n===100) clearInterval(t); },160);
</script>
Stepper
html
<nav aria-label = "Progress">
<ol class="steps">
<li class = "done "> <span> 1 </span> Data </li>
<li class = "current" aria-current = "step "> <span> 2 </span> Documents </li>
<li> <span> 3 </span> Confirmation </li>
</ol>
</nav>
11) Skeleton correct
Use the form of future content (cards/lines), without endless shimmer (or disable with 'prefers-reduced-motion').
Time limit: if loading> 300-500 ms, skeleton is justified; with lower delays, "micro-fade" is enough.
12) Status badges (object states)
Examples are Draft, In Process, Pending Confirmation, Ready, Rejected.
Short text, stable icon/background colors, contrast ≥ AA.
Icon' aria-hidden =" true"' + text label (for SR).
Click - reveal details or open "History."
13) The specifics of iGaming
Rate:- Pressing CTA → "Sent...," with a delay of> 3 seconds - "Waiting for confirmation..." (indeterminate).
- Success - "Bet accepted" + check; error - honest explanation ("market period closed/ratio changed") and safe Retry.
- Determine by stages: "Check method → Send → Confirm PSP."
- For output - In process badge, status screen in profile, ETA range; push on completion.
- Registration stepper (steps), progress to award (N/points), "Participating" status badge.
- Real-time update - neat, no blinks, with 'aria-live = "polite"'.
- Stepper + badge "Under Review." Show what is already accepted (tick) and what is left.
14) Colors, contrast and text
Success/Info/Warning/Danger - four stable tones in the design system.
Text contrast to badge background ≥ AA.
Do not use the same color for "in process" and "warning."
15) Metrics
Time-to-First-Feedback (TTFF): click to first visual response.
Completion Time on operations and drop/abort rate for long tasks.
Retry success rate for progress operations.
% of optimists who completed successfully (and the share of rollbacks).
Visible time skeleton/spinner (goal: as little as possible).
16) Anti-patterns
Silent button (no busy/spinner)> 100 ms.
Infinite spinners without explanation or alternative.
False percentage/99% hung slider.
Resets content on failure and cannot be retried.
Only color without text/icons for status.
Progress is far from the action (user does not see).
17) Design system tokens (example)
json
{
"progress": {
"barHeight": 4,
"radius": 999,
"inMs": 160,
"outMs": 120,
"pollHz": 10
},
"status": {
"tones": { "success": "#", "info": "#", "warning": "#", "danger": "#" },
"badge": { "radius": 8, "px": "6 10", "icon": 14 }
},
"skeleton": {
"rowHeight": 16,
"gap": 8,
"reduceMotion": true
},
"a11y": {
"useAriaBusy": true,
"live": "polite",
"contrastAA": true
}
}
CSS presets:
css
.badge{display:inline-flex; gap:6px; align-items:center; padding:6px 10px; border-radius:8px; font-size:.875rem}
.badge--success{background:var(--bg-success); color:var(--on-success)}
.skeleton{background:linear-gradient(90deg, var(--sk1), var(--sk2), var(--sk1)); border-radius:8px}
@media (prefers-reduced-motion: reduce){.skeleton{background:var(--sk1)} }
18) QA checklist
Response and honesty
- TTFF ≤ 100 ms; there is a local busy/skeleton.
- Determine - real%; indeterminate - with an explanation.
Availability
- 'role = "progressbar" '/' aria-valuenow' correct; live regions on updates.
- Contrast of badges/text ≥ AA; color is not the only bearer of meaning.
Behavior
- Optimistic with correct rollback and explanation.
- Queues are displayed; there is a cancellation/pause (if applicable).
- Progress near the scene does not overlap the CTA.
Performance
- Updates no more than 10-15 times/sec; 'transform/opacity 'animations.
- Skeleton does not tease shimmer with'reduce-motion'.
Texts
- Short, without technical jargon; "what next" after completion.
- No "promises" of exact time unless guaranteed.
19) Documentation in the design system
Компоненты: `ProgressBar`, `ProgressCircle`, `Stepper`, `StatusBadge`, `InlineLoader`, `Skeleton`.
Rules for selecting type, copywriting and colors for statuses.
Patterns: optimistic, queues, background processing, offline synchronization.
Do/Don't gallery: "perpetual spinner," false percentages, "mute" CTA vs good TTFF.
Brief Summary
Indicators of progress and status should provide timely, honest and accessible feedback. Place them alongside the action, distinguish between definite and uncertain progress, respect a11y and don't abuse animations. In iGaming, this is especially important for betting, payments, tournaments and KYC - calm, predictable progress directly increases trust and conversion.