crucıble

Passcode

A segmented one-time-code input: a row of single-character cells backed by real inputs. Typing seats each digit with a soft pop and advances focus, Backspace retreats, arrow keys move, and paste or SMS autofill distributes across cells. The focused empty cell shows an animated caret in an accent ring; a complete code flashes success and fires onComplete. Fully keyboard and screen-reader accessible with a mobile numeric keypad.

motionfree

Installation

CLI

npx shadcn@latest add @crucible/passcode

Manual — install dependencies, then copy the source

npm install motion

Props

PropTypeDefaultDescription
valuestringControlled value — a string of up to length characters. Omit for uncontrolled use.
defaultValuestring""Initial value when uncontrolled.
lengthnumber6Number of single-character cells.
mode"numeric" | "alphanumeric""numeric"Accepted characters. "numeric" allows 0–9 (mobile number pad, one-time-code autofill); "alphanumeric" allows 0–9 and A–Z.
maskedbooleanfalseHide entered characters behind dots (like a PIN).
onChange(value: string) => voidFires on every change with the concatenated value.
onComplete(value: string) => voidFires once every cell is filled, with the complete code.
colors[string, string] | string[]indigo + emerald[accent, success]. Accent lights the focus ring + caret; success flashes the row when the code completes.
speednumber1Animation-speed multiplier for the pop, caret blink and success flash.
pausedbooleanfalseFreeze the caret blink and skip the success flash (still seats instantly).
disabledbooleanfalseDisable all cells.
autoFocusbooleanfalseFocus the first cell on mount.
namestringSubmit name — emits a hidden input carrying the concatenated value.
aria-labelstring"Verification code"Accessible name for the group of cells.
classNamestring

Honors prefers-reduced-motion with a designed static fallback, and passes className through.