@@ -56,7 +56,6 @@ interface OneTimePasswordFieldContextValue {
56
56
name : string | undefined ;
57
57
orientation : Exclude < RovingFocusGroupProps [ 'orientation' ] , undefined > ;
58
58
placeholder : string | undefined ;
59
- preHydrationIndexTracker : React . RefObject < number > ;
60
59
readOnly : boolean ;
61
60
type : InputType ;
62
61
userActionRef : React . RefObject < KeyboardActionDetails | null > ;
@@ -429,13 +428,6 @@ const OneTimePasswordField = React.forwardRef<HTMLDivElement, OneTimePasswordFie
429
428
attemptSubmit ( ) ;
430
429
}
431
430
} , [ attemptSubmit , autoSubmit , currentValue , length , onAutoSubmit , value ] ) ;
432
-
433
- // Before hydration (and in SSR) we can track the index of an input during
434
- // render, as indices calculated by the collection package should almost
435
- // always align with render order anyway. This ensures that index-dependent
436
- // attributes are immediately rendered, in case browser extensions rely on
437
- // those for auto-complete functionality and JS has not hydrated.
438
- const preHydrationIndexTracker = React . useRef < number > ( 0 ) ;
439
431
const isHydrated = useIsHydrated ( ) ;
440
432
441
433
return (
@@ -456,7 +448,6 @@ const OneTimePasswordField = React.forwardRef<HTMLDivElement, OneTimePasswordFie
456
448
dispatch = { dispatch }
457
449
validationType = { validationType }
458
450
orientation = { orientation }
459
- preHydrationIndexTracker = { preHydrationIndexTracker }
460
451
isHydrated = { isHydrated }
461
452
sanitizeValue = { sanitizeValue }
462
453
>
@@ -560,6 +551,12 @@ interface OneTimePasswordFieldInputProps
560
551
* Callback fired when the user input fails native HTML input validation.
561
552
*/
562
553
onInvalidChange ?: ( character : string ) => void ;
554
+ /**
555
+ * User-provided index to determine the order of the inputs. This is useful if
556
+ * you need certain index-based attributes to be set on the initial render,
557
+ * often to prevent flickering after hydration.
558
+ */
559
+ index ?: number ;
563
560
}
564
561
565
562
const OneTimePasswordFieldInput = React . forwardRef <
@@ -569,6 +566,7 @@ const OneTimePasswordFieldInput = React.forwardRef<
569
566
{
570
567
__scopeOneTimePasswordField,
571
568
onInvalidChange,
569
+ index : indexProp ,
572
570
...props
573
571
} : ScopedProps < OneTimePasswordFieldInputProps > ,
574
572
forwardedRef
@@ -592,25 +590,20 @@ const OneTimePasswordFieldInput = React.forwardRef<
592
590
'OneTimePasswordFieldInput' ,
593
591
__scopeOneTimePasswordField
594
592
) ;
595
- const { dispatch, userActionRef, validationType, preHydrationIndexTracker , isHydrated } = context ;
593
+ const { dispatch, userActionRef, validationType, isHydrated } = context ;
596
594
const collection = useCollection ( __scopeOneTimePasswordField ) ;
597
595
const rovingFocusGroupScope = useRovingFocusGroupScope ( __scopeOneTimePasswordField ) ;
598
596
599
597
const inputRef = React . useRef < HTMLInputElement > ( null ) ;
600
598
const [ element , setElement ] = React . useState < HTMLInputElement | null > ( null ) ;
601
599
600
+ const index = indexProp ?? ( element ? collection . indexOf ( element ) : - 1 ) ;
601
+ const canSetPlaceholder = indexProp != null || isHydrated ;
602
602
let placeholder : string | undefined ;
603
- let index : number ;
604
- if ( ! isHydrated ) {
605
- index = preHydrationIndexTracker . current ;
606
- preHydrationIndexTracker . current ++ ;
607
- } else {
608
- index = element ? collection . indexOf ( element ) : - 1 ;
609
- if ( context . placeholder && context . value . length === 0 ) {
610
- // only set placeholder after hydration to prevent flickering when indices
611
- // are re-calculated
612
- placeholder = context . placeholder [ index ] ;
613
- }
603
+ if ( canSetPlaceholder && context . placeholder && context . value . length === 0 ) {
604
+ // only set placeholder after hydration to prevent flickering when indices
605
+ // are re-calculated
606
+ placeholder = context . placeholder [ index ] ;
614
607
}
615
608
616
609
const composedInputRef = useComposedRefs ( forwardedRef , inputRef , setElement ) ;
@@ -640,8 +633,8 @@ const OneTimePasswordFieldInput = React.forwardRef<
640
633
focusable = { ! context . disabled && isFocusable }
641
634
active = { index === lastSelectableIndex }
642
635
>
643
- { ( { isCurrentTabStop } ) => {
644
- const supportsAutoComplete = isHydrated ? isCurrentTabStop : index === 0 ;
636
+ { ( { hasTabStop , isCurrentTabStop } ) => {
637
+ const supportsAutoComplete = hasTabStop ? isCurrentTabStop : index === 0 ;
645
638
return (
646
639
< Primitive . Root . input
647
640
ref = { composedInputRef }
0 commit comments