--- name: ux-feedback-patterns description: User feedback patterns including success/error messages, loading states, confirmations, and progress indicators. Use when implementing notifications, toasts, or status updates. (project) allowed-tools: - Read - Write - Edit - Glob - Grep --- # 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 feedback - **`ux-animation-motion`**: Anime.js animations for feedback effects ## Feedback Types ### 1. Inline Feedback Immediate feedback near the action: ```html Saved successfully ``` ```css .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: ```javascript 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); ``` ```css .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: ```html

Confirm Action

Are you sure you want to proceed?

``` ### 4. Progress Indicators For long-running operations: ```html 60%
Loading...
``` ## Success Feedback ### Visual Patterns ```css /* Success color */ .success { color: var(--color-success); } /* Success icon - use Material Symbol */ /* */ .icon-success { color: var(--color-success); } /* Success border */ .input-success { border-color: var(--color-success); } ``` ### Animation ```javascript import { successBounce, glow } from '../../utils/animations.js'; // On successful action successBounce(element); glow(element, { color: 'rgba(74, 222, 128, 0.6)' }); ``` ### Announcements ```javascript 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 ```css /* 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 ```javascript import { shake } from '../../utils/animations.js'; // On validation failure shake(inputContainer, { intensity: 6 }); ``` ### Error Message Structure ```html
Please enter a valid email address
``` ## Loading States ### Button Loading ```css .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 ```css .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 ```html
Loading game...
``` ## Progress Indicators ### Linear Progress ```css .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 ```html
  1. Step 1
  2. Step 2
  3. Step 3
``` ```css .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 ```css .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 ```html
Score: 42 points
``` ### Alerts ```html
Session expired. Please log in again.
``` ### Implementation ```javascript 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