| Choose between debounce, throttle, or rAF for an event |
Debounce and Throttle |
Use throttle or requestAnimationFrame when you want continuous updates (scroll, mousemove, progress). Use debounce when you want to react once after the user stops (resize, search input, async validation). |
| Trap focus in a modal, implement roving tabindex |
Keyboard Navigation Craft |
Use native HTML for single elements (buttons, links). Use roving tabindex for groups of related controls (tabs, toolbars, menus). |
| Set up IntersectionObserver, scroll-linked state, infinite scroll |
Scroll Interaction Patterns |
Use IntersectionObserver for threshold-based events (entering viewport, lazy load, infinite scroll). Use scroll + rAF for continuous position-linked updates (parallax, progress bars). |
| Build drag-and-drop with touch support and keyboard equivalent |
Drag and Drop Craft |
Use the HTML Drag API for simple desktop-only drag. Use Pointer Events for touch + cross-device support. |
| Update UI immediately before server confirms |
Optimistic UI |
Use optimistic UI when the expected server response is success and failure is rare. Skip it for destructive, financial, or irreversible actions. |
| Detect swipes, pinch, long-press on touch devices |
Touch and Gesture Craft |
Use Pointer Events API for all gestures — it handles mouse, touch, and pen uniformly. Use touch-action CSS to declare which axes you own so the browser can optimize scrolling. |
| Copy to clipboard with visual feedback |
Clipboard and Copy Patterns |
Use navigator.clipboard.writeText() as the primary path on HTTPS. Use navigator.share() for mobile share sheets. |
| Decide when to validate, build autosave, inline editing |
Form Interaction Craft |
Validate on blur for the first time. After the first error, switch to live validation. |
| Sequence, cancel, or coordinate JS animations |
Animation Orchestration |
Use CSS transitions for simple state changes. Use WAAPI (element.animate()) when you need JS-driven values, sequencing, or mid-animation cancellation. |
| Avoid layout thrashing, prevent memory leaks, break up long tasks |
Performance and Event Handling |
Apply these patterns to every JS interaction. Passive listeners, read/write batching, event delegation, and AbortController cleanup are baselines — not optimizations. |