Animated Input
InteractiveA text field with a spring floating label that rises on focus/fill, a centre-drawn accent underline, an optional tinting leading icon, and typed feedback — an error string shakes the field once, paints a live-announced red hint and sets aria-invalid, while success draws a check tick; controlled or uncontrolled with real label/id/aria-describedby wiring. Under prefers-reduced-motion every transition collapses to an instant, legible state (no shake, draw, or float tween) and the focus ring uses :focus-visible.
Inspired by Cult Pro — animated inputs (pattern) — independently built, not affiliated. Attribution policy
Must be at least 8 characters
Installation
npx shadcn@latest add https://parable-three.vercel.app/r/animated-input.jsonRuns the shadcn CLI — the component source is copied intocomponents/parable/animated-input.tsx. You own it from there.
Usage
The exact code rendering the preview above.
<div className="flex w-full max-w-sm flex-col gap-3 px-6">
<AnimatedInput label="Email" type="email" defaultValue="ada@parable.dev" icon={<Mail />} success />
<AnimatedInput label="Full name" icon={<User />} />
<AnimatedInput label="Password" type="password" defaultValue="hunter2" icon={<Lock />} error="Must be at least 8 characters" />
</div>Props
AnimatedInputProps extends Omit< React.InputHTMLAttributes<HTMLInputElement>, "value" | "defaultValue" | "onChange" >
| Prop | Type | Default | Description |
|---|---|---|---|
| label* | React.ReactNode | — | Text of the floating `<label>` (wired to the input via `htmlFor`/`id`). |
| value | string | — | Controlled value. Pair with `onChange`. |
| defaultValue | string | — | Uncontrolled initial value. |
| onChange | (event: React.ChangeEvent<HTMLInputElement>) => void | — | Native change handler; fires on every keystroke in both modes. |
| error | string | — | When set, the field enters its error state: red hint + shake + `aria-invalid`. |
| icon | React.ReactNode | — | Optional decorative leading icon (rendered `aria-hidden`, tints with state). |
| success | boolean | false | Show the drawn success tick on the right (ignored while `error` is set). |
| accent | string | "#8b5cf6" | Accent for the drawn underline, caret, focus ring, and focused label. Mirrors `--pb-violet`. |
| errorColor | string | "#ec4899" | Error tone for the hint, underline, and label. Mirrors `--pb-fuchsia`. |
| successColor | string | "#22d3ee" | Success tone for the tick. Mirrors `--pb-cyan`. |
| ink | string | "#0f0f10" | Backdrop the focus ring offsets against. Mirrors `--pb-ink`. |
npm dependencies
- motion