Pin Input
OTP and PIN entry with auto-advance, smart backspace, and paste spreading.
Paste works too — try it.
"use client";
import { useState } from "react";
import { PinInput, Text, VStack } from "astralis-ui";
export function PinInputDemo() {
const [done, setDone] = useState(false);
return (
<VStack gap="3">
<PinInput length={4} onComplete={() => setDone(true)} onChange={() => setDone(false)} />
<Text size="xs" color={done ? "success" : "muted"}>
{done ? "Code complete — verifying…" : "Paste works too — try it."}
</Text>
</VStack>
);
}Import#
import { PinInput } from "astralis-ui";Usage#
Typing advances to the next box, Backspace at an empty box steps back and
clears, and pasting a full code spreads it across the boxes. onChange
receives the combined string on every keystroke; onComplete fires once
every box is filled — the natural hook for auto-submitting a verification
code.
Masking, types and sizes#
masked, 6 digits, filled
alphanumeric, size lg
"use client";
import { PinInput, Text, VStack } from "astralis-ui";
export function PinInputMask() {
return (
<VStack gap="5" alignItems="start">
<VStack gap="1" alignItems="start">
<Text as="span" size="xs" color="muted">masked, 6 digits, filled</Text>
<PinInput length={6} mask variant="filled" />
</VStack>
<VStack gap="1" alignItems="start">
<Text as="span" size="xs" color="muted">alphanumeric, size lg</Text>
<PinInput length={5} type="alphanumeric" size="lg" placeholder="•" />
</VStack>
</VStack>
);
}Props#
| Prop | Type | Default | Description |
|---|---|---|---|
length | number | 4 | Number of boxes. |
value / defaultValue / onChange | string / string / (value: string) => void | — / "" / — | The combined code. |
onComplete | (value: string) => void | — | Fires when all boxes are filled. |
type | "numeric" | "alpha" | "alphanumeric" | "numeric" | Character validation. |
mask | boolean | false | Bullet display, password-style. |
variant / size | "outline" | "filled" / "sm" | "md" | "lg" | "outline" / "md" | Styling. |
placeholder | string | "○" | Shown in empty boxes. |
autoFocus | boolean | false | Focus the first box on mount. |
invalid / disabled / readOnly | boolean | false | State flags — inherited from Field. |
Keyboard#
| Key | Action |
|---|---|
| type a character | Fill the box and advance to the next |
Backspace | Clear the box; if already empty, move back and clear that one |
Delete | Clear the current box (no movement) |
← / → | Move between boxes without clearing |
| paste | Distribute the pasted characters across the boxes |
Accessibility#
Each box is a real input with a per-cell label ("digit 1 of 4"), reachable with Tab/Shift-Tab; focusing a box selects its content so typing replaces.