KQ-1505 · PIN/SLOTS
Pin Slots
A one-time-code field whose characters drop into their slots: one real, transparent input carries the code, and each new character falls from above on springs.recoil with two small landing bounces while its slot's border catches the colour, the next empty slot holds a glow that slides along on springs.snap, a paste fills every slot in one cascade and Backspace lifts the last character out on the exit ease. When the host accepts the code the slots slide together on springs.snap until the gaps close and lock into one success bar; a refusal shakes the row on a keyframe tween and typing again starts a fresh code. Typing, Backspace, paste and SMS autofill are the browser's own, with the caret held at the end.
Check your phone
We sent a code to the number ending 4821.
It stays valid for ten minutes.
0 of 6 entered · try 246810
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/pin-slots
Props
- value / defaultValue
- string
- default — / ""
- The code, controlled or uncontrolled; anything outside the charset is dropped and it is cut to length.
- onValueChange
- (value: string) => void
- default —
- Fires from the typing, paste or Backspace that changed the code.
- onComplete
- (code: string) => void
- default —
- Fires once, from the keystroke or paste that fills the last slot.
- length
- number
- default 6
- How many slots (1 to 12).
- mask
- boolean
- default false
- Show each character as it lands, then cross-fade it into a dot.
- maskDelay
- number
- default 600
- How long a masked character stays readable, in ms.
- state
- "idle" | "checking" | "success" | "error"
- default "idle"
- The host's verdict: checking dims the glyphs under a passing light, success locks the slots into one bar, error shakes them and turns them danger.
- label
- string
- default "Verification code"
- The input's label, shown above the slots.
- hideLabel
- boolean
- default false
- Keep the label for assistive technology only.
- hint
- string
- default —
- A line under the slots while nothing has been decided.
- successMessage
- string
- default "Code accepted."
- Shown under the bar and announced when state is success.
- errorMessage
- string
- default "That code didn’t match. Try again."
- Shown under the slots and announced when state is error.
- charset
- "numeric" | "alphanumeric"
- default "numeric"
- Digits only with a numeric keypad on phones, or letters and digits, upper-cased.
- split
- number
- default —
- Draw a separator after this many slots, as in 123–456; it folds away when the slots lock.
- size
- "sm" | "md" | "lg"
- default "md"
- Slot size (largest width; narrow rows shrink below it) and glyph size.
- color
- "cobalt" | "signal" | "ember" | "rose" | string
- default "cobalt"
- The caret slot's glow, the caret and the landing flash: a preset tuned for both themes or any CSS colour.
- name
- string
- default —
- A form field name for the input.
- autoFocus
- boolean
- default false
- Focus the input on mount.
- sound
- boolean
- default false
- Tick as each typed or pasted character lands (rising along the row), chime when the slots lock, buzz on a refusal; only for a code the visitor typed.
- disabled
- boolean
- default false
- Disables the input and dims the slots.
- className
- string
- default —
- Classes for the outer column.
| Prop | Type | Default | Description |
|---|---|---|---|
| value / defaultValue | string | — / "" | The code, controlled or uncontrolled; anything outside the charset is dropped and it is cut to length. |
| onValueChange | (value: string) => void | — | Fires from the typing, paste or Backspace that changed the code. |
| onComplete | (code: string) => void | — | Fires once, from the keystroke or paste that fills the last slot. |
| length | number | 6 | How many slots (1 to 12). |
| mask | boolean | false | Show each character as it lands, then cross-fade it into a dot. |
| maskDelay | number | 600 | How long a masked character stays readable, in ms. |
| state | "idle" | "checking" | "success" | "error" | "idle" | The host's verdict: checking dims the glyphs under a passing light, success locks the slots into one bar, error shakes them and turns them danger. |
| label | string | "Verification code" | The input's label, shown above the slots. |
| hideLabel | boolean | false | Keep the label for assistive technology only. |
| hint | string | — | A line under the slots while nothing has been decided. |
| successMessage | string | "Code accepted." | Shown under the bar and announced when state is success. |
| errorMessage | string | "That code didn’t match. Try again." | Shown under the slots and announced when state is error. |
| charset | "numeric" | "alphanumeric" | "numeric" | Digits only with a numeric keypad on phones, or letters and digits, upper-cased. |
| split | number | — | Draw a separator after this many slots, as in 123–456; it folds away when the slots lock. |
| size | "sm" | "md" | "lg" | "md" | Slot size (largest width; narrow rows shrink below it) and glyph size. |
| color | "cobalt" | "signal" | "ember" | "rose" | string | "cobalt" | The caret slot's glow, the caret and the landing flash: a preset tuned for both themes or any CSS colour. |
| name | string | — | A form field name for the input. |
| autoFocus | boolean | false | Focus the input on mount. |
| sound | boolean | false | Tick as each typed or pasted character lands (rising along the row), chime when the slots lock, buzz on a refusal; only for a code the visitor typed. |
| disabled | boolean | false | Disables the input and dims the slots. |
| className | string | — | Classes for the outer column. |