Learning Track
Filter content by your role to see the most relevant sections
Feedback & Status Patterns
Tell users the truth about system state: the alert-versus-status announcement distinction, toasts that stack and expire honestly, loading states that match actual waiting, and empty states designed as screens rather than silences.
Why This Matters
Every interface is having a conversation about state—did that work? is this loading? why is this empty?—whether anyone designed the conversation or not. Silence is an answer users hate: they resubmit forms, they reload pages, they conclude the app is broken. Feedback design is the discipline of answering at the right urgency, through the right channel, at the right moment.
The wrong urgency is its own failure class: everything announcing as an emergency trains users to ignore emergencies. This system's family—Alert, AlertNotice, Toast, Skeleton, Spinner, Progress, Status—exists to make urgency a chosen property, declared in the component contracts and expressed through the accessibility tree's two announcement channels.
Core Concepts: Two Channels, Four Urgencies
The Announcement Distinction: Alert vs Status
The accessibility tree has exactly two polite-volume channels for spontaneous announcements, and they encode urgency. The Toast contract declares both because the component serves both:
// ui/components/Toast/Toast.contract.json (excerpt)
"role": "alert",
"roles": ["alert", "status"]
// role="alert" → assertive: interrupts, for what matters NOW
// (failures, destructive confirmations)
// role="status" → polite: announces at the next breath
// (successes, completions)
// Choosing the channel IS choosing the urgency.The discipline that keeps both usable: reserve assertive for what deserves interruption. A success toast on alert is the boy who cried wolf in ARIA form.
The Urgency Ladder
- Inline (Field.Error): scoped to one control, adjacent, persistent until fixed. The lowest urgency and the highest precision.
- Banner (Alert/AlertNotice):page-scoped, persistent, dismissible when actionable. For what changes the page's meaning.
- Toast: transient, stacked, for confirmations of actions the user just took. Success on
status; failure onalertwith an action to retry. - Blocking (dialog): reserved for decisions, not information—the overlay pattern's territory, borrowed never.
Loading States That Tell the Truth
A spinner is a promise about time. Keep the promise honest with the system's own timing vocabulary: under ~300ms (duration.medium0), show nothing—flash-of-loading is its own insult; to ~1s (long0), a spinner or Skeleton suffices; beyond that, Progress with real information, because an unbounded wait with a boundless animation is a lie with a spinner on it. Skeletons add the shape promise: they placeholders the layout of what is coming, so arrival does not reflow the world (the motion system's reduced-motion contract applies to shimmer too—fades, not sweeps).
Empty States Are Screens
"No results" is a screen with a job: explain why it is empty, and offer the next move (clear filters, create the first thing, learn what belongs here). An empty state that is a bare sentence abandons the user at exactly the moment they need direction most. It is navigation wearing quiet clothes.
Optimistic Honesty
Optimistic UI (act succeeded, correct later if wrong) is a feedback strategy, not an escape from it: the optimistic state must be visually distinct from confirmed, rollbacks must announce as clearly as the original success, and the pattern is honest only where reversal is cheap. Confident where cheap, honest where not.
System Roles: Owning the Conversation
Design Impact
Designers own the urgency assignments—the ladder mapped per message type—and the empty states, which are design work wearing humility.
Engineering Impact
Engineers own the channel wiring: alert vs status per contract, stacking order (newest where attention already is), timers that respect the duration vocabulary, and rollbacks that announce.
Accessibility Impact
The a11y function owns announcement etiquette: nothing assertive without cause, no stacked announcements colliding, and the manual pass confirming the tree says what the pixels imply.
Design & Code Interplay
The design side of feedback is the message inventory: every state the product can announce, its urgency ladder position, its channel, and its lifespan—drawn as a matrix, reviewed as one. Teams that skip the matrix ship urgency by accident.
The ladder, as assembled:
// Inline: scoped, persistent, precise
<Field.Error role="alert">{error}</Field.Error>
// Toast: transient, stacked, channeled by urgency
toast.success('Project saved', { role: 'status' }); // polite
toast.failure('Save failed', { role: 'alert', // assertive
action: { label: 'Retry', onActivate: retry } });
// Loading: honest about time
{elapsed < 300 ? null
: elapsed < 1000 ? <Spinner label="Loading" />
: <Progress value={percent} label="Importing" />}
// Empty: a screen with a job
<EmptyState title="No projects yet"
body="Projects hold your tokens and docs."
action={<Button onClick={create}>Create project</Button>} />Applied Example: The Save Flow, End to End
One action—the document save—through the whole family:
- Trigger: Cmd+S. If under 300ms round-trip is expected, act optimistically: the title flickers to saving styling (distinct, quiet).
- Waiting: beyond a second, the button shows Progress—truth about time, not a spinner pretending.
- Success: a toast on
status—polite, 4s life, no action needed; the optimistic styling resolves to confirmed. - Failure: a toast on
alertwith Retry; the document reverts visibly; nothing is silently lost. - Verify: the announcement pass—both channels heard, no collisions, rollbacks as audible as successes.
Constraints & Trade-offs
- Toast transience vs persistence: disappearing confirmations respect attention and outrun slow readers—critical messages persist or log somewhere retrievable.
- Optimism vs certainty: optimistic UI feels instant and lies sometimes; blocking feels slow and never lies. The cost of being wrong decides.
- Skeleton fidelity vs maintenance: high-fidelity skeletons promise the layout precisely and must track it; low-fidelity ones age better and reflow more.
Common Pitfalls & Failure Modes
1. Assertive everything
// Bad: Every announcement interrupts
<div role="alert">Welcome back!</div>
// Good: Urgency is chosen; welcome is status or nothing2. The eternal spinner
An animation with no information. Past a second, progress needs a dimension—percent, steps, or honest uncertainty language.
3. Success nobody can hear
Visual-only confirmation for an action a screen reader user took. If the user acted, the tree answers.
4. The silent rollback
Optimistic state vanishing without announcement—the user believes the save happened. Rollbacks announce on alert, always.
5. Empty as dead end
"No results" with no path forward. Every empty state names the next move.
Verification Checklist
Additional Resources
- Forms — the inline tier of the ladder (
/blueprints/ux-patterns/forms) - Motion & Duration — the timing vocabulary loading states borrow (
/blueprints/foundations/motion) - ARIA live regions — the channels themselves (
https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions)
Related Concepts
Reflection Questions
Apply This Concept
Build the message inventory for a product you touch: state, urgency, channel, lifespan for every announcement. Which entries were accidental, and what did fixing the worst one change?
Reflect
An optimistic save feels instant but fails 1-in-50 times. Argue the rollback announcement design, and what the failure rate would have to be for you to abandon optimism.
