Skip to content

Commit 36914f5

Browse files
tofikwestclaude
andauthored
Fix collapsed OTP input boxes in portal login (#2153)
* fix: update OTP input to modern children + context API The InputOTPSlot component used the deprecated render prop pattern from input-otp v1.x which caused the OTP boxes to collapse. Updated to the modern children-based API using OTPInputContext, matching the approach used by @trycompai/design-system. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: handle undefined slot in InputOTPSlot for type safety Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b1b072e commit 36914f5

2 files changed

Lines changed: 14 additions & 15 deletions

File tree

apps/portal/src/app/components/otp-form.tsx

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,13 @@ export function OtpForm({ email }: OtpFormProps) {
7171
render={({ field }) => (
7272
<FormItem>
7373
<FormControl>
74-
<InputOTP
75-
maxLength={INPUT_LENGTH}
76-
{...field}
77-
render={({ slots }) => (
78-
<InputOTPGroup>
79-
{slots.map((slot, index) => (
80-
<InputOTPSlot key={index} {...slot} />
81-
))}
82-
</InputOTPGroup>
83-
)}
84-
/>
74+
<InputOTP maxLength={INPUT_LENGTH} {...field}>
75+
<InputOTPGroup>
76+
{Array.from({ length: INPUT_LENGTH }, (_, i) => (
77+
<InputOTPSlot key={i} index={i} />
78+
))}
79+
</InputOTPGroup>
80+
</InputOTP>
8581
</FormControl>
8682
<FormMessage />
8783
</FormItem>

packages/ui/src/components/input-otp.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { DashIcon } from '@radix-ui/react-icons';
4-
import { OTPInput, type SlotProps } from 'input-otp';
4+
import { OTPInput, OTPInputContext } from 'input-otp';
55
import * as React from 'react';
66
import { cn } from '../utils';
77

@@ -23,13 +23,16 @@ InputOTPGroup.displayName = 'InputOTPGroup';
2323

2424
const InputOTPSlot = React.forwardRef<
2525
React.ElementRef<'div'>,
26-
SlotProps & React.ComponentPropsWithoutRef<'div'>
27-
>(({ char, hasFakeCaret, isActive, className, placeholderChar, ...props }, ref) => {
26+
React.ComponentPropsWithoutRef<'div'> & { index: number }
27+
>(({ index, className, ...props }, ref) => {
28+
const inputOTPContext = React.useContext(OTPInputContext);
29+
const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
30+
2831
return (
2932
<div
3033
ref={ref}
3134
className={cn(
32-
'border-input relative flex h-16 w-16 items-center justify-center border-y border-r text-2xl transition-all first:rounded-l-md first:border-l last:rounded-r-md',
35+
'border-input relative flex h-10 w-10 items-center justify-center border-y border-r text-lg transition-all first:rounded-l-md first:border-l last:rounded-r-md',
3336
isActive && 'ring-ring z-10 ring-1',
3437
className,
3538
)}

0 commit comments

Comments
 (0)