Skip to content
NewService Map: 30 components for hosts, ports and routes
<PxOtp />ReactFormsForm controlFree

One-time code

Six-digit one-time-code field backed by one real input, so typing, paste and code autofill work; a wrong code shakes and falls away.

View as Markdown
<PxOtp />

Trytype 424242, then something else.

Playground

Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.

Loading <PxOtp />
Props
codelive
hintlive
disabledlive
React
<PxOtp code="424242" hint="Demo code: 424242" />

Installation

pnpm dlx shadcn@latest add @lumesec/px-otp
First timeRegister the @lumesec registry once, or install by URL+

Adds @lumesec to your components.json:

pnpm dlx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json

Or skip the setup and install by URL:

npx shadcn@latest add https://elements.lumesec.ai/r/px-otp.json

Usage

px-otp-example.tsx
import { PxOtp } from "@/components/lumesec/px-otp";

export function Example() {
  return (
    <PxOtp
      name="code"
      onComplete={(code, valid) => {
        if (valid) console.log("verify", code);
      }}
    />
  );
}

Behaviour

Six boxes backed by one real input, so typing, pasting and the phone’s one-time-code autofill all work. Digits rise into their boxes; a wrong code shakes and falls away.

API reference

Props

Also accepts every prop of <div> (React.ComponentProps<"div">), spread onto the root element.

valueTypestring

Controlled digits entered so far. Use with onValueChange.

defaultValueTypestringDefault""

Initial digits when uncontrolled.

codeTypestring

Expected code. When set, a complete entry is compared with it; when missing, any six digits are valid.

hintTypestringDefault"Enter the 6-digit code"

Message under the boxes until a code is checked, and again after reset().

nameTypestring

Form field name; the digits submit under it.

disabledTypebooleanDefaultfalse

Dims the boxes and disables the input.

onValueChangeType(value: string) => void

Called with the digits entered so far on every change.

onCompleteType(code: string, valid: boolean) => void

Called when the sixth digit is entered, with the code and whether it matched code.

Ref

ref receives a PxOtpHandle handle with these methods.

reset(): void

Clears the digits and the result, and shows the hint again.

focus(): void

Moves focus into the code input.

Keyboard

KeysAction
ArrowLeft / ArrowRight / Home / EndIgnored, so the caret stays at the end of the code.

Accessibility

  • One native <input> with inputmode="numeric", autocomplete="one-time-code" and aria-label="6-digit code" covers the boxes. The boxes are drawn on an aria-hidden canvas and the digits in them are aria-hidden text, so assistive technology reads the input's value.
  • The message line is an aria-live="polite" region, so "Code verified" and the mismatch message are announced.
  • After a wrong code the field clears and focus returns to the input; after a correct code the input loses focus.
  • A native <input> submits the digits entered so far under name. It never reports itself invalid; after a wrong code the value is cleared 650 ms later. Form reset works like reset().
  • Reduced motion: digits appear in place without rising, and the success sparks and error shake are skipped; removed digits still break into pixels.

Theming

Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from --lumesec. See Theming.

This component reads --foreground, --muted-foreground, --lumesec, --lumesec-shine, --lumesec-success and --destructive.

Notes

  • The comparison with code runs in the browser, so the expected code is visible to anyone who looks; treat it as a demo aid and verify codes on the server.
  • Digits are text in the mono font with tabular figures. They rise into their boxes; a removed digit breaks into pixels sampled from its glyph, and a rejected code falls away as red pixels.
  • After a correct code, further typing is ignored until reset() is called.
  • Non-digits are stripped and input stops at six digits, so a pasted or autofilled "424 242" completes. Messages are in English.
  • The root carries data-state="ok" or data-state="error" while a result shows.

Was this page helpful?