Marble UI
← Components

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>

PropTypeDefaultDescription
classNamestring—
defaultValuestring—
descriptionReactNode—
disabledboolean—
groupSizenumber—Insert a visual separator after this many characters (e.g. 3 → "123-456").
labelReactNode—
lengthnumber6
maskboolean—
onValueChange(value: string) => void—
onValueComplete(value: string) => void—
validationType'none' | 'numeric' | 'alphanumeric' | 'alpha'—
valuestring—
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. onValueComplete fires when every slot is filled.
  • length defaults to 6. validationType is numeric, alphanumeric, alpha or none; mask hides the characters.
  • variant is boxes or joined; groupSize inserts a visual separator (3 gives “123-456”).
  • This is not a React Aria field, so there is no isDisabled or errorMessage: use disabled and show errors yourself, for example in description.
Example source · show
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