Input OTP
A one-time-code input primitive that keeps a real native value while mirroring characters into visible slots.
import { InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot } from 'radcn/input-otp'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.
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.
