feat(form): ✨ Add shake animation for error alerts in sign-in form#713
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Code Review
This pull request introduces a shake animation effect for form validation errors using motion/react. It defines shared shake keyframes and transitions, applies them to form fields via a new AutoFormField wrapper component, and wraps the sign-in form's error alert in an animated component. The reviewer pointed out that the sign-in error alert's shake animation will not replay on consecutive identical submission errors because the animate prop remains constant. They suggested using the useAnimate hook to imperatively trigger the animation on every error occurrence, matching the behavior implemented in AutoFormField.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const shouldReduceMotion = useReducedMotion(); | ||
| const { onSubmit, error, formSchema } = useFormSignIn({ isAdmin }); | ||
|
|
||
| return ( | ||
| <div className="space-y-4"> | ||
| {error && ( | ||
| <Alert variant="destructive"> | ||
| <AlertCircle className="size-4" /> | ||
| <AlertTitle>{t(`errors.${error}.title`)}</AlertTitle> | ||
| <AlertDescription>{t(`errors.${error}.desc`)}</AlertDescription> | ||
| </Alert> | ||
| <motion.div | ||
| animate={shouldReduceMotion ? undefined : SHAKE_KEYFRAMES} | ||
| transition={SHAKE_TRANSITION} | ||
| > | ||
| <Alert variant="destructive"> | ||
| <AlertCircle className="size-4" /> | ||
| <AlertTitle>{t(`errors.${error}.title`)}</AlertTitle> | ||
| <AlertDescription>{t(`errors.${error}.desc`)}</AlertDescription> | ||
| </Alert> | ||
| </motion.div> | ||
| )} |
There was a problem hiding this comment.
The current implementation of the shake animation will only trigger the first time an error is displayed. If the user submits the form again and the same error occurs, the animation will not replay because the animate prop on motion.div remains a constant. This is inconsistent with the field-level error animations, which shake on every invalid submission.
To ensure the animation plays on every error, I recommend using the useAnimate hook, similar to how it's used for AutoFormField. This gives you imperative control to trigger the animation.
You'll also need to adjust your imports:
import { useAnimate, useReducedMotion } from 'motion/react';
import { useEffect } from 'react';Note: For this useEffect to re-trigger on consecutive identical errors, the error state from useFormSignIn should be a new object/value for each submission failure. For example, instead of just a string, it could be an object like { message: 'the_error', id: Date.now() }.
const shouldReduceMotion = useReducedMotion();
const { onSubmit, error, formSchema } = useFormSignIn({ isAdmin });
const [scope, animate] = useAnimate<HTMLDivElement>();
useEffect(() => {
if (error && !shouldReduceMotion && scope.current) {
animate(scope.current, SHAKE_KEYFRAMES, SHAKE_TRANSITION);
}
}, [error, animate, scope, shouldReduceMotion]);
return (
<div className="space-y-4">
{error && (
<div ref={scope}>
<Alert variant="destructive">
<AlertCircle className="size-4" />
<AlertTitle>{t(`errors.${error}.title`)}</AlertTitle>
<AlertDescription>{t(`errors.${error}.desc`)}</AlertDescription>
</Alert>
</div>
)}
Improving Documentation
pnpm lint:fixto fix formatting issues before opening the PR.Description
What?
Why?