ux-feedback-patterns
UX Feedback Patterns Skill
User feedback mechanisms for communicating state changes, success, errors, and progress. This skill covers visual, auditory, and haptic feedback patterns.
Related Skills
material-symbols-v3: Icon names for status indicators (check_circle,error,warning)ux-iconography: Icon + text patterns for feedbackux-animation-motion: Anime.js animations for feedback effects
Feedback Types
1. Inline Feedback
Immediate feedback near the action:
<button>Save</button>
<span class="inline-feedback" role="status" aria-live="polite">
Saved successfully
</span>
.inline-feedback {
font-size: var(--step--1);
color: var(--color-success);
opacity: 0;
transition: opacity 0.2s ease;
}
.inline-feedback.visible {
opacity: 1;
}
2. Toast Notifications
Non-blocking temporary messages as a web component:
class ToastContainer extends HTMLElement {
#container; // Direct reference - NO querySelector
constructor() {
super();
this.attachShadow({ mode: 'open' });
// Build and store direct reference
this.#container = document.createElement('div');
this.#container.className = 'toast-container';
this.#container.setAttribute('part', 'container');
this.shadowRoot.appendChild(this.#container);
}
show(message, type = 'info', duration = 3000) {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.setAttribute('role', 'alert');
toast.setAttribute('part', 'toast');
toast.textContent = message;
this.#container.appendChild(toast); // Direct reference
// Auto-dismiss
setTimeout(() => {
toast.classList.add('exiting');
toast.addEventListener('animationend', () => toast.remove());
}, duration);
}
}
customElements.define('toast-container', ToastContainer);
.toast {
padding: var(--space-s) var(--space-m);
background: var(--theme-surface-variant);
border-radius: var(--space-2xs);
animation: slideIn 0.2s ease;
}
.toast-success {
border-left: 4px solid var(--color-success);
}
.toast-error {
border-left: 4px solid var(--color-error);
}
.toast.exiting {
animation: slideOut 0.2s ease forwards;
}
3. Confirmation Dialogs
For destructive or important actions:
<dialog class="confirm-dialog">
<h2>Confirm Action</h2>
<p>Are you sure you want to proceed?</p>
<div class="dialog-actions">
<button class="btn-secondary">Cancel</button>
<button class="btn-danger">Delete</button>
</div>
</dialog>
4. Progress Indicators
For long-running operations:
<!-- Determinate progress -->
<progress value="60" max="100" aria-label="Upload progress">60%</progress>
<!-- Indeterminate/spinner -->
<div class="spinner" role="status" aria-label="Loading">
<span class="sr-only">Loading...</span>
</div>
Success Feedback
Visual Patterns
/* Success color */
.success {
color: var(--color-success);
}
/* Success icon - use Material Symbol */
/* <span class="icon" aria-hidden="true">check_circle</span> */
.icon-success {
color: var(--color-success);
}
/* Success border */
.input-success {
border-color: var(--color-success);
}
Animation
import { successBounce, glow } from '../../utils/animations.js';
// On successful action
successBounce(element);
glow(element, { color: 'rgba(74, 222, 128, 0.6)' });
Announcements
announce(message) {
// For screen readers
this.#announcer.textContent = '';
requestAnimationFrame(() => {
this.#announcer.textContent = message;
});
}
// Usage
this.announce('Word completed! 3 points earned.');
Error Feedback
Visual Patterns
/* Error color */
.error {
color: var(--color-error);
}
/* Error state */
[aria-invalid="true"] {
border-color: var(--color-error);
}
/* Error message */
.error-message {
color: var(--color-error);
font-size: var(--step--1);
}
Shake Animation
import { shake } from '../../utils/animations.js';
// On validation failure
shake(inputContainer, { intensity: 6 });
Error Message Structure
<div class="field">
<input aria-invalid="true" aria-describedby="error-1">
<span id="error-1" class="error-message" role="alert">
Please enter a valid email address
</span>
</div>
Loading States
Button Loading
.button[aria-busy="true"] {
position: relative;
color: transparent;
pointer-events: none;
}
.button[aria-busy="true"]::after {
content: '';
position: absolute;
inset: 0;
margin: auto;
width: 1em;
height: 1em;
border: 2px solid currentColor;
border-right-color: transparent;
border-radius: 50%;
animation: spin 0.6s linear infinite;
}
Skeleton Loading
.skeleton {
background: linear-gradient(
90deg,
var(--theme-surface-variant) 25%,
var(--theme-surface) 50%,
var(--theme-surface-variant) 75%
);
background-size: 200% 100%;
animation: shimmer 1.5s infinite;
border-radius: var(--space-2xs);
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
Page Loading
<div class="loading-overlay" role="status">
<div class="spinner"></div>
<span class="sr-only">Loading game...</span>
</div>
Progress Indicators
Linear Progress
.progress-bar {
height: 4px;
background: var(--theme-outline-variant);
border-radius: 2px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background: var(--theme-primary);
transition: width 0.3s ease;
}
Step Progress
<ol class="steps" aria-label="Progress">
<li data-status="complete" aria-current="false">Step 1</li>
<li data-status="current" aria-current="step">Step 2</li>
<li data-status="pending" aria-current="false">Step 3</li>
</ol>
.steps [data-status="complete"] {
color: var(--color-success);
}
.steps [data-status="current"] {
color: var(--theme-primary);
font-weight: 600;
}
.steps [data-status="pending"] {
color: var(--theme-on-surface-variant);
}
Circular Progress
.progress-circle {
--progress: 0;
width: 60px;
height: 60px;
border-radius: 50%;
background: conic-gradient(
var(--theme-primary) calc(var(--progress) * 1%),
var(--theme-outline-variant) 0
);
}
Live Regions
Status Updates
<div role="status" aria-live="polite" aria-atomic="true">
Score: 42 points
</div>
Alerts
<div role="alert" aria-live="assertive">
Session expired. Please log in again.
</div>
Implementation
class Announcer {
#region;
constructor() {
this.#region = document.createElement('div');
this.#region.setAttribute('role', 'status');
this.#region.setAttribute('aria-live', 'polite');
this.#region.setAttribute('aria-atomic', 'true');
this.#region.className = 'sr-only';
document.body.appendChild(this.#region);
}
announce(message, priority = 'polite') {
this.#region.setAttribute('aria-live', priority);
this.#region.textContent = '';
requestAnimationFrame(() => {
this.#region.textContent = message;
});
}
}
Timing Guidelines
| Feedback Type | Duration | Use Case |
|---|---|---|
| Micro-animation | 100-200ms | Button press, toggle |
| State transition | 200-300ms | Page change, modal |
| Toast display | 3-5 seconds | Success message |
| Error display | Until dismissed | Validation error |
| Loading indicator | Immediate | Any async operation |
Accessibility Checklist
- Success/error announced to screen readers
- Focus moved to relevant element after action
- Loading states communicated with
aria-busy - Progress communicated with proper ARIA
- Animations respect
prefers-reduced-motion - Color is not the only indicator of state
- Error messages are associated with inputs
More from matthewharwood/fantasy-phonics
animejs-v4
Anime.js 4.0 animations for Web Components — drag-drop, click feedback, swaps, cancelable motion. Use when adding animations, drag interactions, visual feedback, or motion to custom elements. Combines with web-components-architecture for lifecycle cleanup.
37ux-spacing-layout
Utopia fluid spacing tokens and layout patterns. Use when applying margins, padding, gaps, or creating layouts. Covers space scale, container widths, and responsive spacing. (project)
15ux-iconography
Icon usage patterns using Material Symbols v3. Use when adding icons to buttons, navigation, or status indicators. Covers sizing, accessibility, animations, and color integration with project tokens.
10ux-design-principles
Cognitive psychology principles for UX design decisions. Use when planning features, structuring interfaces, reducing complexity, or optimizing user journeys. Covers choice architecture, cognitive load, attention, and experience design. (project)
9web-audio
Production-tested patterns for fault-tolerant browser audio with zero-lag rapid-fire support. Use when implementing sound effects, background music, voice feedback, or any audio playback in web applications. Covers AudioContext singleton, preloading, cloneNode for rapid-fire, autoplay handling, and Web Audio API effects.
8ux-typography
Typography patterns using Utopia fluid type scale with cqi units. Use when setting font sizes, line heights, font families, or text styling. Covers display vs body fonts, hierarchy, and readability. (project)
6