Overview
Form-validation error shake is a tiny keyframe animation (translate-X back and forth a few pixels) triggered when an input fails validation. The pattern adds the .is-shaking class on submit, force-reflows the element with void el.offsetWidth, then re-adds the class so the keyframe restarts even on rapid resubmits. An aria-live="polite" region announces the validation message in parallel.
When to use it
Reach for shake feedback on inline form validation, permission-denied taps, “wrong password” affordances — any rejection that the user needs to notice without leaving their current context. Skip it for any error that requires an action beyond “fix the input” (network errors, server errors); those need a toast or a modal with explicit next steps.
How it works
A 5-frame @keyframes rule named shake translates the element along the X axis with diminishing amplitude (e.g. 0% / 25% / 50% / 75% / 100% at 0px / -8px / 6px / -4px / 0px) over ~320ms. Adding the class kicks it off; the trick is restarting it on the same element — CSS animations do not replay when re-applied to a node that already has the class. The canonical fix: remove the class, read void el.offsetWidth to force a synchronous reflow, then re-add the class. The browser now sees a fresh animation start and the keyframe replays from frame 0.
Production gotchas
Forgetting the reflow trick is the most common bug — the user mashes submit, the error message updates, but the input never shakes again. Tying the shake to animationend with class removal is fine, but racing it against rapid resubmits means the class can be removed before the next add triggers reflow; use requestAnimationFrame bracketing if shakes feel inconsistent. Keep the amplitude under ~8px — large translations are uncomfortable on tightly-packed forms and can collide with adjacent layout.
Accessibility
Shake is a decorative reinforcement — the error announcement itself must come from aria-live="polite" or role="alert" with the actual validation message. Under prefers-reduced-motion: reduce swap the translate keyframe for a brief border-color flash (red 80% opacity for 200ms then back) so the error still reads without the lateral motion that can trigger vestibular disorders.
References
Implementation depth
Shake feedback should be a secondary cue after a clear error message. The animation can draw the eye to the invalid field, but text and aria-describedby need to explain what the user must fix.
Keep the distance small and the duration short. Large shake motion feels punitive and can be uncomfortable; reduced motion should use color, border, and message changes without lateral movement.