Moodinary/UI

Input OTP

Códigos cortos (verificación, código de equipo en kiosco). Pegar reparte los dígitos.

Primitiva disponible sin uso actual en la app. No representa el acceso corto del pulso ni el flujo de autenticación. Pegar reparte el contenido y descarta caracteres no numéricos por defecto.

Instalación

shadcn
npx shadcn@latest add https://design.moodinary.com/r/input-otp.json
import
import { InputOtp } from "@moodinary/ui/components/input-otp";

Ejemplos

Ingreso, código válido y error

Escribí o pegá 123456 para ver la confirmación. Cualquier otro código completo muestra el mensaje de error. Es una demostración local, no una verificación real.

Código de demostración. Probá 123456.

Código
default.tsx
"use client";

import { InputOtp } from "@moodinary/ui/components/input-otp";
import { cn } from "@moodinary/ui/lib/utils";
import { useState } from "react";

function otpMessage(complete: boolean, ok: boolean): string {
	if (!complete) {
		return "Código de demostración. Probá 123456.";
	}
	return ok ? "Código correcto." : "Código incorrecto. Probá 123456.";
}

export default function InputOtpDefault() {
	const [code, setCode] = useState("");
	const complete = code.length === 6;
	const ok = code === "123456";

	return (
		<div className="flex flex-col gap-2">
			<InputOtp
				aria-describedby="otp-msg"
				aria-invalid={complete && !ok}
				aria-label="Código de 6 dígitos"
				className={
					complete && !ok
						? "[&_input]:border-m1 [&_input]:ring-3 [&_input]:ring-m1/15"
						: undefined
				}
				onValueChange={setCode}
				value={code}
			/>
			<p
				aria-live="polite"
				className={cn(
					"text-ink-3 text-xs",
					complete && (ok ? "text-m5" : "text-m1")
				)}
				id="otp-msg"
			>
				{otpMessage(complete, ok)}
			</p>
		</div>
	);
}

Props

InputOtp

PropTipoDefaultDescripción
lengthnumber6Cantidad de casillas; si es par, agrega un separador a la mitad.
value / defaultValuestring-Código controlado o inicial.
onValueChange(value: string, details: OTPField.Root.ChangeEventDetails) => void-Recibe el código completo al editar o pegar.
onValueComplete(value: string, details: OTPField.Root.CompleteEventDetails) => void-Se dispara al completar todas las casillas.
validationType"numeric" | "alpha" | "alphanumeric" | "none""numeric"Filtro de caracteres de Base UI.
autoCompletestring"one-time-code"Permite el autocompletado del código.
disabled / readOnlybooleanfalseBloquea interacción o edición.
namestring-Identifica el valor completo en el formulario.

Cuándo sí y cuándo no

Hacé
  • Permití pegar el código completo.
  • Mostrá cómo corregir un código rechazado.
  • Verificá el código en el servidor, nunca en el componente.
Evitá
  • No obligues a tipear cada casilla por separado.
  • No confundas completar el código con validarlo.
  • No uses el código de ejemplo en un flujo real.

Accesibilidad

  • Cada casilla anuncia su número; las flechas recorren los dígitos.
  • Backspace borra y permite retroceder; pegar distribuye el valor.
  • Conectá la ayuda con aria-describedby y anunciá el resultado completo, no cada pulsación.