Accessible & Unstyled One Time Passcode Input For React

A customizable, accessible, easy-to-style one-time passcode input for React apps.

How to use it:

1. Install and import the component.

# NPM
$ npm install input-otp
import { OTPInput } from 'input-otp'

2. Basic usage.

<OTPInput
  maxLength={6}
  containerClassName="group flex items-center has-[:disabled]:opacity-30"
  render={({ slots }) => (
    <>
      <div className="flex">
        {slots.slice(0, 3).map((slot, idx) => (
          <Slot key={idx} {...slot} />
        ))}
      </div>
      <FakeDash />
      <div className="flex">
        {slots.slice(3).map((slot, idx) => (
          <Slot key={idx} {...slot} />
        ))}
      </div>
    </>
  )}
/>
// Feel free to copy. Uses @shadcn/ui tailwind colors.
function Slot(props: { char: string | null; isActive: boolean }) {
  return (
    <div
      className={cn(
        'relative w-10 h-14 text-[2rem]',
        'flex items-center justify-center',
        'transition-all duration-300',
        'border-border border-y border-r first:border-l first:rounded-l-md last:rounded-r-md',
        'group-hover:border-accent-foreground/20 group-focus-within:border-accent-foreground/20',
        'outline outline-0 outline-accent-foreground/20',
        { 'outline-4 outline-accent-foreground': props.isActive },
      )}
    >
      {props.char !== null && <div>{props.char}</div>}
      {props.char === null && props.isActive && <FakeCaret />}
    </div>
  )
}
// You can emulate a fake textbox caret!
function FakeCaret() {
  return (
    <div className="absolute pointer-events-none inset-0 flex items-center justify-center animate-caret-blink">
      <div className="w-px h-8 bg-white" />
    </div>
  )
}
// Inspired by Stripe's MFA input.
function FakeDash() {
  return (
    <div className="flex w-10 justify-center items-center">
      <div className="w-3 h-1 rounded-full bg-border" />
    </div>
  )
}
// Tailwind.config.ts for the blinking caret animation.
const config = {
  theme: {
    extend: {
      keyframes: {
        'caret-blink': {
          '0%,70%,100%': { opacity: '1' },
          '20%,50%': { opacity: '0' },
        },
      },
      animation: {
        'caret-blink': 'caret-blink 1.2s ease-out infinite',
      },
    },
  },
}
// Small utility to merge class names.
import { clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import type { ClassValue } from "clsx";
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

3. Available component props.

value?: string
onChange?: (...args: any[]) => unknown
maxLength: number
allowNavigation?: boolean
inputMode?: 'numeric' | 'text'
onComplete?: (...args: any[]) => unknown
render: (props: OTPInputRenderProps) => React.ReactElement
containerClassName?: string

Preview:

Accessible & Unstyled One Time Passcode Input For React

Download Details:

Author: guilhermerodz

Live Demo: View The Demo

Download Link: Download The Source Code

Official Website: https://github.com/guilhermerodz/input-otp

License: MIT

Add Comment