OTP Field
Preview: Boxes
One-time code input (Base UI OTP Field): paste, autofill and per-slot keyboard handling built in.
Import
import { OTPField } from '@marbleui/ui'Props
<OTPField>
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | |
| defaultValue | string | — | |
| description | ReactNode | — | |
| disabled | boolean | — | |
| groupSize | number | — | Insert a visual separator after this many characters (e.g. 3 → "123-456"). |
| label | ReactNode | — | |
| length | number | 6 | |
| mask | boolean | — | |
| onValueChange | (value: string) => void | — | |
| onValueComplete | (value: string) => void | — | |
| validationType | 'none' | 'numeric' | 'alphanumeric' | 'alpha' | — | |
| value | string | — | |
| variant | 'boxes' | 'joined' | 'boxes' |
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitive: Base UI OTPField. Follow the primitive's docs for the full keyboard map.
Usage notes
One-time code input with one box per character, built on Base UI OTPField (paste and autofill handled). For a single free-form value use TextField.
<OTPField
label="Verification code"
length={6}
onValueComplete={(code) => verify(code)}
/>
- Uncontrolled:
defaultValue. Controlled:value+onValueChange.onValueCompletefires when every slot is filled. lengthdefaults to 6.validationTypeisnumeric,alphanumeric,alphaornone;maskhides the characters.variantisboxesorjoined;groupSizeinserts a visual separator (3 gives “123-456”).- This is not a React Aria field, so there is no
isDisabledorerrorMessage: usedisabledand show errors yourself, for example indescription.
Example source · show· hide
import { useState } from 'react'
import { OTPField } from './otp-field'
function Verify() {
const [status, setStatus] = useState<'idle' | 'ok'>('idle')
return (
<div className="flex flex-col items-center gap-3">
<OTPField
label="Verification code"
description={status === 'ok' ? 'Code accepted.' : 'Enter the 6-digit code we sent to your phone.'}
onValueComplete={() => setStatus('ok')}
onValueChange={() => setStatus('idle')}
/>
</div>
)
}
export const styles = {
Boxes: Verify,
Grouped: () => <OTPField label="Sign-in code" variant="joined" groupSize={3} />,
Alphanumeric: () => <OTPField label="Invite code" length={8} groupSize={4} validationType="alphanumeric" defaultValue="AB12" />,
}Source: packages/ui/src/otp-field/otp-field.tsx
Catalog
- Category
- inputs
- Priority
- Foundation
- Primitive
- base-ui
- Base UI
- OTP Field