LoadingIndicator signals that work is in progress—GraphQL fetches, report generation, attachment uploads. It answers "is anything happening?" without blocking the whole shell unless the operation truly requires it. Pair with a skeleton for longer waits to preserve layout stability; a spinner alone on a blank region undermines perceived performance compared to a skeleton that hints at the incoming shape.
- Inline fetches in buttons, cards, or table footers where duration is uncertain but short-to-medium.
- Full-region loading when content can't render meaningfully and a skeleton is unavailable.
- Sub-200ms operations where the spinner flashes. Omit or debounce display.
- Determinate processes with a known progress value—use
Progress.
- Background tasks better surfaced through a
Snackbar completion toast.
- Small inline with text or in table cells.
- Regular default for page regions.
- Large hero loading for dashboards where the spinner is the only visual.
- Accompanying text names the task ("Loading incidents…") and updates for multi-step flows. Localize via
formatMessage.
- Show once the wait threshold passes; hide promptly on completion to avoid flicker loops.
- On failure, transition to a
Callout or field errors; don't spin indefinitely.
Do
- Align spinner placement with where content will land, to minimize layout shift on resolve.
- Keep dashboard spinners subordinate—covering an entire incident console is a last resort.
Don't
- Stack multiple large spinners in one viewport. Consolidate status.
- Use animated spinners for
prefers-reduced-motion users without swapping to a static busy indicator per the implementation.
Expose aria-busy on relevant regions; announcements should be polite, not chatty under fast polling. See Accessibility for the full contract.
- Skeleton for layout-preserving loads.
- Progress for determinate operations.
- Button for in-button loading states.