PIN / OTP Input
A row of single-character fields that auto-advance — perfect for OTP verification, PIN entry, and short codes.
Basic Usage
6-digit code
Auto-advances to the next field as the user types. Paste a full code into any field to fill all six.
import { PinInput } from 'fluxo-ui';
const [code, setCode] = useState('');
<PinInput
length={6}
value={code}
onChange={setCode}
onComplete={(v) => verify(v)}
autoFocus
/>Variants
Box (default)
Bordered tiles — most familiar OTP look.
Underline
Only a bottom rule — minimal chrome for clean forms.
Soft
Filled background with no visible border — pairs well with light backgrounds.
<PinInput length={4} variant="box" />
<PinInput length={4} variant="underline" />
<PinInput length={4} variant="soft" />Sizes
Small
Compact fields for inline forms.
Medium (default)
Balanced size for typical OTP screens.
Large
Bigger touch targets — ideal for sign-in screens on mobile.
<PinInput length={6} size="sm" />
<PinInput length={6} size="md" />
<PinInput length={6} size="lg" />Advanced
Grouped digits
Insert a visual separator every N fields with groupAfter.
Alphanumeric + masked
type='alphanumeric' allows letters and digits; mask hides characters as dots.
Password with placeholder
Use type='password' for secret codes; add a placeholder character to indicate empty slots.
Error state
Mark the group invalid and add an errorText to announce the issue via role=alert.
<PinInput length={6} groupAfter={3} type="numeric" />
<PinInput length={8} type="alphanumeric" mask />
<PinInput length={4} type="password" placeholder="•" />
<PinInput length={6} invalid errorText="Incorrect code" />Import
import { PinInput } from 'fluxo-ui';
import type { PinInputProps, PinInputVariant, PinInputSize, PinInputType } from 'fluxo-ui';Props
lengthnumber"6"Number of digit/character fields.
lengthnumber"6"Number of digit/character fields.
valuestringControlled value of the combined code.
valuestringControlled value of the combined code.
defaultValuestring"''"Initial value when uncontrolled.
defaultValuestring"''"Initial value when uncontrolled.
onChange(value: string) => voidCalled on every character change.
onChange(value: string) => voidCalled on every character change.
onComplete(value: string) => voidCalled when all fields are filled.
onComplete(value: string) => voidCalled when all fields are filled.
type'numeric' | 'alphanumeric' | 'password'"'numeric'"Allowed character set. 'password' also masks input.
type'numeric' | 'alphanumeric' | 'password'"'numeric'"Allowed character set. 'password' also masks input.
maskboolean"false"Mask characters as dots/asterisks even if type isn't password.
maskboolean"false"Mask characters as dots/asterisks even if type isn't password.
variant'box' | 'underline' | 'soft'"'box'"Visual style. 'box' is a bordered tile, 'underline' uses a bottom border only, 'soft' uses a filled background.
variant'box' | 'underline' | 'soft'"'box'"Visual style. 'box' is a bordered tile, 'underline' uses a bottom border only, 'soft' uses a filled background.
size'sm' | 'md' | 'lg'"'md'"Visual size of each field.
size'sm' | 'md' | 'lg'"'md'"Visual size of each field.
disabledboolean"false"Disable all fields.
disabledboolean"false"Disable all fields.
autoFocusboolean"false"Auto-focus the first field on mount.
autoFocusboolean"false"Auto-focus the first field on mount.
placeholderstring"''"Placeholder character for empty fields.
placeholderstring"''"Placeholder character for empty fields.
groupAfternumberInsert a visual separator after every N fields (e.g., 3 for 3-3 grouping).
groupAfternumberInsert a visual separator after every N fields (e.g., 3 for 3-3 grouping).
invalidboolean"false"Show error styling on the fields.
invalidboolean"false"Show error styling on the fields.
namestringName prefix used for each <input> (rendered as `${name}-${index}`).
namestringName prefix used for each <input> (rendered as `${name}-${index}`).
classNamestringAdditional CSS class for the root.
classNamestringAdditional CSS class for the root.
ariaLabelstring"'Verification code'"Accessible name for the group.
ariaLabelstring"'Verification code'"Accessible name for the group.
Features
Auto-advance
Typing a character moves focus to the next field; Backspace moves back.
Paste support
Pasting a full code distributes characters across remaining fields.
Three variants
box, underline, and soft — match any form aesthetic.
Numeric / alphanumeric / password
Input mode adapts so mobile keyboards show the right layout.
One-time-code autocomplete
autoComplete="one-time-code" enables iOS SMS auto-fill.
Invalid state
Error styling with role=alert announcement support.