Pin Input

Short codes, one cell per character, paste-friendly.

v1.0.0·Updated Jul 8, 2026 · 10:45
Live Demo — Fully Interactive
Type — focus jumps forward; Backspace jumps back
Configuration
Length
Size
Masking
State
4819
<PinInput length={4} />
Behavior — The Engineering Contract
Prop / eventTypeNotes
lengthnumberNumber of cells (typically 4–6)
onComplete(code) => voidFires when every cell is filled
maskbooleanRenders • instead of the character
statuserror · successBorder colour across all cells
type · BackspaceAuto-advance; empty Backspace steps back
pasteSpreads a pasted code across the cells

Use a Pin Input for a short, fixed-length code. For longer or free-form secrets use a password Input.

Anatomy
48
1Filled cellHolds one character; lighter border once set.
2Active cellThe focused cell wears the warm ring.
3Empty cellAwaiting input; the count is always visible.
Do's and Don'ts
✓ Do
4819

Match the cell count to the real code length. Four cells for four digits.

✕ Don't

Don't use cells for long inputs. Nine tiny boxes is a password field.

✓ Do
1234

Turn every cell red on a wrong code, then let them retry cleanly.

✕ Don't
41

Don't let focus scatter. Typing and pasting must fill left to right.

In context: Examples
A · 2FA
481920

Six-digit codes from an authenticator or SMS, auto-submitting.

B · PIN entry

Masked cells for a private PIN or unlock code.

C · Invite code
A7K2

Alphanumeric access codes, one character per cell.

Measurements & Tokens
TokenValueRole
--pin-cell44 × 52pxCell size (38 × 46 small)
--pin-gap10pxSpace between cells
--pin-font1.2rem monoCentred character
--pin-bg#0E0F12Cell fill
--pin-focusrgba(255,122,0,.14)3px warm ring on the active cell
--pin-error#EB4A4FWrong-code border on all cells
Code
<div class="o-pin" role="group" aria-label="Verification code">
  <input class="o-pin__cell" inputmode="numeric" maxlength="1" aria-label="Digit 1" />
  <input class="o-pin__cell" inputmode="numeric" maxlength="1" aria-label="Digit 2" />
  <input class="o-pin__cell" inputmode="numeric" maxlength="1" aria-label="Digit 3" />
  <input class="o-pin__cell" inputmode="numeric" maxlength="1" aria-label="Digit 4" />
</div>