@@ -66,32 +66,39 @@ InputOTPGroup.displayName = 'InputOTPGroup'
6666 *
6767 * Uses emcn design tokens for consistent styling with the Input component.
6868 */
69- const InputOTPSlot = React . forwardRef <
70- React . ElementRef < 'div' > ,
71- React . ComponentPropsWithoutRef < 'div' > & { index : number }
72- > ( ( { index, className, ...props } , ref ) => {
73- const inputOTPContext = React . useContext ( OTPInputContext )
74- const { char, hasFakeCaret, isActive } = inputOTPContext . slots [ index ]
69+ export interface InputOTPSlotProps extends React . ComponentPropsWithoutRef < 'div' > {
70+ /** Zero-based position of this slot in the OTP input. */
71+ index : number
72+ /** Keep the error border visible even while this slot is active. */
73+ invalid ?: boolean
74+ }
75+
76+ const InputOTPSlot = React . forwardRef < React . ElementRef < 'div' > , InputOTPSlotProps > (
77+ ( { index, invalid = false , className, ...props } , ref ) => {
78+ const inputOTPContext = React . useContext ( OTPInputContext )
79+ const { char, hasFakeCaret, isActive } = inputOTPContext . slots [ index ]
7580
76- return (
77- < div
78- ref = { ref }
79- className = { cn (
80- 'relative flex h-12 w-12 items-center justify-center rounded-sm border border-[var(--border-1)] bg-[var(--surface-5)] text-[var(--text-primary)] text-lg transition-colors' ,
81- isActive && 'z-10 border-[var(--text-muted)] ring-1 ring-[var(--text-muted)]' ,
82- className
83- ) }
84- { ...props }
85- >
86- { char }
87- { hasFakeCaret && (
88- < div className = 'pointer-events-none absolute inset-0 flex items-center justify-center' >
89- < div className = 'h-6 w-px animate-caret-blink bg-[var(--text-primary)] duration-1000 motion-reduce:animate-none' />
90- </ div >
91- ) }
92- </ div >
93- )
94- } )
81+ return (
82+ < div
83+ ref = { ref }
84+ className = { cn (
85+ 'relative flex h-12 w-12 items-center justify-center rounded-sm border border-[var(--border-1)] bg-[var(--surface-5)] text-[var(--text-primary)] text-lg transition-colors' ,
86+ isActive && 'z-10 border-[var(--text-muted)] ring-1 ring-[var(--text-muted)]' ,
87+ invalid && 'border-[var(--text-error)]' ,
88+ className
89+ ) }
90+ { ...props }
91+ >
92+ { char }
93+ { hasFakeCaret && (
94+ < div className = 'pointer-events-none absolute inset-0 flex items-center justify-center' >
95+ < div className = 'h-6 w-px animate-caret-blink bg-[var(--text-primary)] duration-1000 motion-reduce:animate-none' />
96+ </ div >
97+ ) }
98+ </ div >
99+ )
100+ }
101+ )
95102InputOTPSlot . displayName = 'InputOTPSlot'
96103
97104/**
0 commit comments