RadCN
Inputsreadycomponentready

Input OTP

A one-time-code input primitive that keeps a real native value while mirroring characters into visible slots.

Importimport { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'radcn/input-otp'
Preview

Live package example

Render the four upstream Input OTP examples with RadCN slots, separators, patterns, and app-owned display state.

Example Parity

Render the four upstream Input OTP examples with RadCN slots, separators, patterns, and app-owned display state.

Preview

Letters and numbers are accepted.

Enter your one-time password.

import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, REGEXP_ONLY_DIGITS_AND_CHARS } from 'radcn/input-otp'

export function InputOTPExamples() {
  return (
    <>
      <InputOTP ariaLabel="One-time code" maxLength={6}>
        <InputOTPGroup>
          <InputOTPSlot index={0} />
          <InputOTPSlot index={1} />
          <InputOTPSlot index={2} />
        </InputOTPGroup>
        <InputOTPSeparator />
        <InputOTPGroup>
          <InputOTPSlot index={3} />
          <InputOTPSlot index={4} />
          <InputOTPSlot index={5} />
        </InputOTPGroup>
      </InputOTP>

      <InputOTP ariaLabel="Alphanumeric code" maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}>
        <InputOTPGroup>
          <InputOTPSlot index={0} />
          <InputOTPSlot index={1} />
          <InputOTPSlot index={2} />
          <InputOTPSlot index={3} />
          <InputOTPSlot index={4} />
          <InputOTPSlot index={5} />
        </InputOTPGroup>
      </InputOTP>
    </>
  )
}

Installation

Intended future install command. RadCN is private and not published to npm yet, so this snippet documents the target user-facing API rather than something external consumers can run today.

pnpm add radcn # intended future package
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'radcn/input-otp'

Theming

RadCN tokens read the resolved theme from the document. Store the user's preference separately, then resolve system preferences to a concrete light or dark theme before setting package tokens.

<html data-radcn-theme-mode="system" data-radcn-theme="dark">
  ...
</html>

Accessibility

  • InputOTP renders a native text input with autocomplete="one-time-code", maxLength, name, required, disabled, and invalid state.
  • Visible slots mirror the native input value while the native input remains the form and accessibility owner.
  • InputOTPSeparator renders role="separator" for grouped visual code layouts.
  • Keyboard movement, paste filtering, form submission, and reset behavior stay native-input based.

Customization

  • InputOTP exposes public data-radcn-input-otp hooks for root, native input, slots container, groups, slots, caret, and separators.
  • Use class for the input and containerClass for the visible slot shell; style and CSS variables remain app-owned extension points.
  • REGEXP_ONLY_DIGITS_AND_CHARS is exported by RadCN and maps to dependency-free native pattern filtering.
  • Controlled entered-value display text is app-owned browser/server state layered around the native value and radcn-input-otp-change event.

Remix 3 Notes

  • React useState, value, and onChange examples map to explicit RadCN props, native input events, radcn-input-otp-change, or app-owned state.
  • The upstream input-otp package and OTPInput context are not RadCN dependencies; RadCN implements the required behavior with a native input and slots.
  • lucide-react separator icons are app-owned presentation; InputOTPSeparator works without icon dependencies.
  • Tailwind utilities map to class, containerClass, style, CSS variables, and app-authored CSS.
  • className maps to class, containerClassName maps to containerClass, data-slot maps to data-radcn-input-otp-* hooks, and vendor source remains read-only evidence.
  • input-otp-form and otp-* block recipes are adjacent form/block evidence rather than part of this four-example cluster.