Skip to content
uiify

Input OTP

Input for one-time codes, with one slot per character.

Browsers
Chrome 123+, Firefox 121+, Safari 17.5+
Tier
2
Bundle compressed
1.69 kB
Forced layout budget
0 ms
Axe budget
0
SSR compatible
Yes
Published contract
Test harness

Playground

State
import { InputOTP, InputOTPHiddenInput, InputOTPSlot } from "@gunkin/uiify";

export default function Example() {
  return (
    <InputOTP id="verification-code" length={6}>
      {Array.from({ length: 6 }, (_, index) => (
        <InputOTPSlot index={index} key={index} />
      ))}
      <InputOTPHiddenInput />
    </InputOTP>
  );
}

API

InputOTPHiddenInput

PropTypeDefaultDescription
autoFocusboolean——
render(props: Record<string, unknown> & { ref?: Ref<HTMLInputElement>; }, state: { disabled: boolean; }) => ReactElement<unknown, string | JSXElementConstructor<any>> | null——
asElementType"input"—

InputOTP

PropTypeDefaultDescription
autoFocusbooleanfalse—
defaultValuestring""—
disabledbooleanfalse—
idstring——
lengthnumber6—
maskbooleanfalse—
patternstring——
sizeControlSize—Sets the control's height and text size; `md` is the default.
typeInputOTPType"numeric"—
onValueChange(value: string) => void——
onComplete(value: string) => void——
valuestring——
render(props: Record<string, unknown> & { ref?: Ref<HTMLElement>; }, state: InputOTPShellOwnProps & InputOTPControlledOwnProps) => ReactElement<...> | null——
asElementType"div"—

InputOTPSlot

PropTypeDefaultDescription
indexnumber——
render(props: Record<string, unknown> & { ref?: Ref<HTMLElement>; }, state: { active: boolean; filled: boolean; }) => ReactElement<unknown, string | JSXElementConstructor<any>> | null——
asElementType"div"—

Keyboard

KeyAction
Type / pasteFill the slots from the start
BackspaceDelete the last character

Accessibility

One native text input, InputOTPHiddenInput, holds the whole code with autocomplete="one-time-code" and the name "One-time code", so typing, paste and autofill reach the form as one value. The slots are aria-hidden visuals that follow it after hydration. Keep visible instructions next to the slots.

Styling hooks

  • data-completeroot, every slot filled
  • data-disabled
  • data-activeslot
  • data-filledslot
  • data-indexslot