@@ -116,6 +116,10 @@ interface StateDefinition<T> {
116116
117117  isTyping : boolean 
118118
119+   inputElement : HTMLInputElement  |  null 
120+   buttonElement : HTMLButtonElement  |  null 
121+   optionsElement : HTMLElement  |  null 
122+ 
119123  __demoMode : boolean 
120124} 
121125
@@ -132,6 +136,10 @@ enum ActionTypes {
132136  SetActivationTrigger , 
133137
134138  UpdateVirtualConfiguration , 
139+ 
140+   SetInputElement , 
141+   SetButtonElement , 
142+   SetOptionsElement , 
135143} 
136144
137145function  adjustOrderedState < T > ( 
@@ -192,6 +200,9 @@ type Actions<T> =
192200      options : T [ ] 
193201      disabled : ( ( value : any )  =>  boolean )  |  null 
194202    } 
203+   |  {  type : ActionTypes . SetInputElement ;  element : HTMLInputElement  |  null  } 
204+   |  {  type : ActionTypes . SetButtonElement ;  element : HTMLButtonElement  |  null  } 
205+   |  {  type : ActionTypes . SetOptionsElement ;  element : HTMLElement  |  null  } 
195206
196207let  reducers : { 
197208  [ P  in  ActionTypes ] : < T > ( 
@@ -245,7 +256,7 @@ let reducers: {
245256  [ ActionTypes . GoToOption ] ( state ,  action )  { 
246257    if  ( state . dataRef . current ?. disabled )  return  state 
247258    if  ( 
248-       state . dataRef . current ?. optionsRef . current  && 
259+       state . optionsElement  && 
249260      ! state . dataRef . current ?. optionsPropsRef . current . static  && 
250261      state . comboboxState  ===  ComboboxState . Closed 
251262    )  { 
@@ -419,6 +430,18 @@ let reducers: {
419430      virtual : {  options : action . options ,  disabled : action . disabled  ??  ( ( )  =>  false )  } , 
420431    } 
421432  } , 
433+   [ ActionTypes . SetInputElement ] : ( state ,  action )  =>  { 
434+     if  ( state . inputElement  ===  action . element )  return  state 
435+     return  {  ...state ,  inputElement : action . element  } 
436+   } , 
437+   [ ActionTypes . SetButtonElement ] : ( state ,  action )  =>  { 
438+     if  ( state . buttonElement  ===  action . element )  return  state 
439+     return  {  ...state ,  buttonElement : action . element  } 
440+   } , 
441+   [ ActionTypes . SetOptionsElement ] : ( state ,  action )  =>  { 
442+     if  ( state . optionsElement  ===  action . element )  return  state 
443+     return  {  ...state ,  optionsElement : action . element  } 
444+   } , 
422445} 
423446
424447let  ComboboxActionsContext  =  createContext < { 
@@ -431,6 +454,10 @@ let ComboboxActionsContext = createContext<{
431454  selectActiveOption ( ) : void 
432455  setActivationTrigger ( trigger : ActivationTrigger ) : void 
433456  onChange ( value : unknown ) : void 
457+ 
458+   setInputElement ( element : HTMLInputElement  |  null ) : void 
459+   setButtonElement ( element : HTMLButtonElement  |  null ) : void 
460+   setOptionsElement ( element : HTMLElement  |  null ) : void 
434461}  |  null > ( null ) 
435462ComboboxActionsContext . displayName  =  'ComboboxActionsContext' 
436463
@@ -455,7 +482,7 @@ function VirtualProvider(props: {
455482  let  {  options }  =  data . virtual ! 
456483
457484  let  [ paddingStart ,  paddingEnd ]  =  useMemo ( ( )  =>  { 
458-     let  el  =  data . optionsRef . current 
485+     let  el  =  data . optionsElement 
459486    if  ( ! el )  return  [ 0 ,  0 ] 
460487
461488    let  styles  =  window . getComputedStyle ( el ) 
@@ -464,7 +491,7 @@ function VirtualProvider(props: {
464491      parseFloat ( styles . paddingBlockStart  ||  styles . paddingTop ) , 
465492      parseFloat ( styles . paddingBlockEnd  ||  styles . paddingBottom ) , 
466493    ] 
467-   } ,  [ data . optionsRef . current ] ) 
494+   } ,  [ data . optionsElement ] ) 
468495
469496  let  virtualizer  =  useVirtualizer ( { 
470497    enabled : options . length  !==  0 , 
@@ -475,7 +502,7 @@ function VirtualProvider(props: {
475502      return  40 
476503    } , 
477504    getScrollElement ( )  { 
478-       return  ( data . optionsRef . current   ??   null )   as   HTMLElement   |   null 
505+       return  data . optionsElement 
479506    } , 
480507    overscan : 12 , 
481508  } ) 
@@ -573,10 +600,6 @@ let ComboboxDataContext = createContext<
573600        static : boolean 
574601        hold : boolean 
575602      } > 
576- 
577-       inputRef : MutableRefObject < HTMLInputElement  |  null > 
578-       buttonRef : MutableRefObject < HTMLButtonElement  |  null > 
579-       optionsRef : MutableRefObject < HTMLElement  |  null > 
580603    }  &  Omit < StateDefinition < unknown > ,  'dataRef' > ) 
581604  |  null 
582605> ( null ) 
@@ -688,17 +711,16 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
688711      : null , 
689712    activeOptionIndex : null , 
690713    activationTrigger : ActivationTrigger . Other , 
714+     inputElement : null , 
715+     buttonElement : null , 
716+     optionsElement : null , 
691717    __demoMode, 
692718  }  as  StateDefinition < TValue > ) 
693719
694720  let  defaultToFirstOption  =  useRef ( false ) 
695721
696722  let  optionsPropsRef  =  useRef < _Data [ 'optionsPropsRef' ] [ 'current' ] > ( {  static : false ,  hold : false  } ) 
697723
698-   let  inputRef  =  useRef < _Data [ 'inputRef' ] [ 'current' ] > ( null ) 
699-   let  buttonRef  =  useRef < _Data [ 'buttonRef' ] [ 'current' ] > ( null ) 
700-   let  optionsRef  =  useRef < _Data [ 'optionsRef' ] [ 'current' ] > ( null ) 
701- 
702724  type  TActualValue  =  true  extends  typeof  multiple  ? EnsureArray < TValue > [ number ]  : TValue 
703725  let  compare  =  useByComparator < TActualValue > ( by ) 
704726
@@ -733,9 +755,6 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
733755      ...state , 
734756      immediate, 
735757      optionsPropsRef, 
736-       inputRef, 
737-       buttonRef, 
738-       optionsRef, 
739758      value, 
740759      defaultValue, 
741760      disabled, 
@@ -791,8 +810,10 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
791810
792811  // Handle outside click 
793812  let  outsideClickEnabled  =  data . comboboxState  ===  ComboboxState . Open 
794-   useOutsideClick ( outsideClickEnabled ,  [ data . buttonRef ,  data . inputRef ,  data . optionsRef ] ,  ( )  => 
795-     actions . closeCombobox ( ) 
813+   useOutsideClick ( 
814+     outsideClickEnabled , 
815+     [ data . buttonElement ,  data . inputElement ,  data . optionsElement ] , 
816+     ( )  =>  actions . closeCombobox ( ) 
796817  ) 
797818
798819  let  slot  =  useMemo ( ( )  =>  { 
@@ -896,6 +917,18 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
896917    dispatch ( {  type : ActionTypes . SetActivationTrigger ,  trigger } ) 
897918  } ) 
898919
920+   let  setInputElement  =  useEvent ( ( element : HTMLInputElement  |  null )  =>  { 
921+     dispatch ( {  type : ActionTypes . SetInputElement ,  element } ) 
922+   } ) 
923+ 
924+   let  setButtonElement  =  useEvent ( ( element : HTMLButtonElement  |  null )  =>  { 
925+     dispatch ( {  type : ActionTypes . SetButtonElement ,  element } ) 
926+   } ) 
927+ 
928+   let  setOptionsElement  =  useEvent ( ( element : HTMLElement  |  null )  =>  { 
929+     dispatch ( {  type : ActionTypes . SetOptionsElement ,  element } ) 
930+   } ) 
931+ 
899932  let  actions  =  useMemo < _Actions > ( 
900933    ( )  =>  ( { 
901934      onChange, 
@@ -906,6 +939,9 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
906939      openCombobox, 
907940      setActivationTrigger, 
908941      selectActiveOption, 
942+       setInputElement, 
943+       setButtonElement, 
944+       setOptionsElement, 
909945    } ) , 
910946    [ ] 
911947  ) 
@@ -923,7 +959,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
923959    < LabelProvider 
924960      value = { labelledby } 
925961      props = { { 
926-         htmlFor : data . inputRef . current ?. id , 
962+         htmlFor : data . inputElement ?. id , 
927963      } } 
928964      slot = { { 
929965        open : data . comboboxState  ===  ComboboxState . Open , 
@@ -1019,15 +1055,16 @@ function InputFn<
10191055    ...theirProps 
10201056  }  =  props 
10211057
1022-   let  inputRef  =  useSyncRefs ( data . inputRef ,  ref ,  useFloatingReference ( ) ) 
1023-   let  ownerDocument  =  useOwnerDocument ( data . inputRef ) 
1058+   let  internalInputRef  =  useRef < HTMLInputElement  |  null > ( null ) 
1059+   let  inputRef  =  useSyncRefs ( internalInputRef ,  ref ,  useFloatingReference ( ) ,  actions . setInputElement ) 
1060+   let  ownerDocument  =  useOwnerDocument ( data . inputElement ) 
10241061
10251062  let  d  =  useDisposables ( ) 
10261063
10271064  let  clear  =  useEvent ( ( )  =>  { 
10281065    actions . onChange ( null ) 
1029-     if  ( data . optionsRef . current )  { 
1030-       data . optionsRef . current . scrollTop  =  0 
1066+     if  ( data . optionsElement )  { 
1067+       data . optionsElement . scrollTop  =  0 
10311068    } 
10321069    actions . goToOption ( Focus . Nothing ) 
10331070  } ) 
@@ -1071,7 +1108,7 @@ function InputFn<
10711108      // using an IME, we don't want to mess with the input at all. 
10721109      if  ( data . isTyping )  return 
10731110
1074-       let  input  =  data . inputRef . current 
1111+       let  input  =  internalInputRef . current 
10751112      if  ( ! input )  return 
10761113
10771114      if  ( oldState  ===  ComboboxState . Open  &&  state  ===  ComboboxState . Closed )  { 
@@ -1121,7 +1158,7 @@ function InputFn<
11211158        // using an IME, we don't want to mess with the input at all. 
11221159        if  ( data . isTyping )  return 
11231160
1124-         let  input  =  data . inputRef . current 
1161+         let  input  =  internalInputRef . current 
11251162        if  ( ! input )  return 
11261163
11271164        // Capture current state 
@@ -1232,7 +1269,7 @@ function InputFn<
12321269      case  Keys . Escape :
12331270        if  ( data . comboboxState  !==  ComboboxState . Open )  return 
12341271        event . preventDefault ( ) 
1235-         if  ( data . optionsRef . current  &&  ! data . optionsPropsRef . current . static )  { 
1272+         if  ( data . optionsElement  &&  ! data . optionsPropsRef . current . static )  { 
12361273          event . stopPropagation ( ) 
12371274        } 
12381275
@@ -1286,10 +1323,10 @@ function InputFn<
12861323      ( event . relatedTarget  as  HTMLElement )  ??  history . find ( ( x )  =>  x  !==  event . currentTarget ) 
12871324
12881325    // Focus is moved into the list, we don't want to close yet. 
1289-     if  ( data . optionsRef . current ?. contains ( relatedTarget ) )  return 
1326+     if  ( data . optionsElement ?. contains ( relatedTarget ) )  return 
12901327
12911328    // Focus is moved to the button, we don't want to close yet. 
1292-     if  ( data . buttonRef . current ?. contains ( relatedTarget ) )  return 
1329+     if  ( data . buttonElement ?. contains ( relatedTarget ) )  return 
12931330
12941331    // Focus is moved, but the combobox is not open. This can mean two things: 
12951332    // 
@@ -1316,8 +1353,8 @@ function InputFn<
13161353  let  handleFocus  =  useEvent ( ( event : ReactFocusEvent )  =>  { 
13171354    let  relatedTarget  = 
13181355      ( event . relatedTarget  as  HTMLElement )  ??  history . find ( ( x )  =>  x  !==  event . currentTarget ) 
1319-     if  ( data . buttonRef . current ?. contains ( relatedTarget ) )  return 
1320-     if  ( data . optionsRef . current ?. contains ( relatedTarget ) )  return 
1356+     if  ( data . buttonElement ?. contains ( relatedTarget ) )  return 
1357+     if  ( data . optionsElement ?. contains ( relatedTarget ) )  return 
13211358    if  ( data . disabled )  return 
13221359
13231360    if  ( ! data . immediate )  return 
@@ -1378,7 +1415,7 @@ function InputFn<
13781415      id, 
13791416      role : 'combobox' , 
13801417      type, 
1381-       'aria-controls' : data . optionsRef . current ?. id , 
1418+       'aria-controls' : data . optionsElement ?. id , 
13821419      'aria-expanded' : data . comboboxState  ===  ComboboxState . Open , 
13831420      'aria-activedescendant' :
13841421        data . activeOptionIndex  ===  null 
@@ -1457,7 +1494,8 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
14571494)  { 
14581495  let  data  =  useData ( 'Combobox.Button' ) 
14591496  let  actions  =  useActions ( 'Combobox.Button' ) 
1460-   let  buttonRef  =  useSyncRefs ( data . buttonRef ,  ref ) 
1497+   let  buttonRef  =  useSyncRefs ( ref ,  actions . setButtonElement ) 
1498+ 
14611499  let  internalId  =  useId ( ) 
14621500  let  { 
14631501    id =  `headlessui-combobox-button-${ internalId }  ` , 
@@ -1466,7 +1504,7 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
14661504    ...theirProps 
14671505  }  =  props 
14681506
1469-   let  refocusInput  =  useRefocusableInput ( data . inputRef ) 
1507+   let  refocusInput  =  useRefocusableInput ( data . inputElement ) 
14701508
14711509  let  handleKeyDown  =  useEvent ( ( event : ReactKeyboardEvent < HTMLElement > )  =>  { 
14721510    switch  ( event . key )  { 
@@ -1505,7 +1543,7 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
15051543      case  Keys . Escape :
15061544        if  ( data . comboboxState  !==  ComboboxState . Open )  return 
15071545        event . preventDefault ( ) 
1508-         if  ( data . optionsRef . current  &&  ! data . optionsPropsRef . current . static )  { 
1546+         if  ( data . optionsElement  &&  ! data . optionsPropsRef . current . static )  { 
15091547          event . stopPropagation ( ) 
15101548        } 
15111549        flushSync ( ( )  =>  actions . closeCombobox ( ) ) 
@@ -1561,10 +1599,10 @@ function ButtonFn<TTag extends ElementType = typeof DEFAULT_BUTTON_TAG>(
15611599    { 
15621600      ref : buttonRef , 
15631601      id, 
1564-       type : useResolveButtonType ( props ,  data . buttonRef ) , 
1602+       type : useResolveButtonType ( props ,  data . buttonElement ) , 
15651603      tabIndex : - 1 , 
15661604      'aria-haspopup' : 'listbox' , 
1567-       'aria-controls' : data . optionsRef . current ?. id , 
1605+       'aria-controls' : data . optionsElement ?. id , 
15681606      'aria-expanded' : data . comboboxState  ===  ComboboxState . Open , 
15691607      'aria-labelledby' : labelledBy , 
15701608      disabled : disabled  ||  undefined , 
@@ -1635,20 +1673,20 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
16351673
16361674  let  [ floatingRef ,  style ]  =  useFloatingPanel ( anchor ) 
16371675  let  getFloatingPanelProps  =  useFloatingPanelProps ( ) 
1638-   let  optionsRef  =  useSyncRefs ( data . optionsRef ,   ref ,  anchor  ? floatingRef  : null ) 
1639-   let  ownerDocument  =  useOwnerDocument ( data . optionsRef ) 
1676+   let  optionsRef  =  useSyncRefs ( ref ,  anchor  ? floatingRef  : null ,   actions . setOptionsElement ) 
1677+   let  ownerDocument  =  useOwnerDocument ( data . optionsElement ) 
16401678
16411679  let  usesOpenClosedState  =  useOpenClosed ( ) 
16421680  let  [ visible ,  transitionData ]  =  useTransition ( 
16431681    transition , 
1644-     data . optionsRef , 
1682+     data . optionsElement , 
16451683    usesOpenClosedState  !==  null 
16461684      ? ( usesOpenClosedState  &  State . Open )  ===  State . Open 
16471685      : data . comboboxState  ===  ComboboxState . Open 
16481686  ) 
16491687
16501688  // Ensure we close the combobox as soon as the input becomes hidden 
1651-   useOnDisappear ( visible ,  data . inputRef ,  actions . closeCombobox ) 
1689+   useOnDisappear ( visible ,  data . inputElement ,  actions . closeCombobox ) 
16521690
16531691  // Enable scroll locking when the combobox is visible, and `modal` is enabled 
16541692  let  scrollLockEnabled  =  data . __demoMode 
@@ -1661,11 +1699,10 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
16611699    ? false 
16621700    : modal  &&  data . comboboxState  ===  ComboboxState . Open 
16631701  useInertOthers ( inertOthersEnabled ,  { 
1664-     allowed : useEvent ( ( )  =>  [ 
1665-       data . inputRef . current , 
1666-       data . buttonRef . current , 
1667-       data . optionsRef . current , 
1668-     ] ) , 
1702+     allowed : useCallback ( 
1703+       ( )  =>  [ data . inputElement ,  data . buttonElement ,  data . optionsElement ] , 
1704+       [ data . inputElement ,  data . buttonElement ,  data . optionsElement ] 
1705+     ) , 
16691706  } ) 
16701707
16711708  useIsoMorphicEffect ( ( )  =>  { 
@@ -1676,7 +1713,7 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
16761713  } ,  [ data . optionsPropsRef ,  hold ] ) 
16771714
16781715  useTreeWalker ( data . comboboxState  ===  ComboboxState . Open ,  { 
1679-     container : data . optionsRef . current , 
1716+     container : data . optionsElement , 
16801717    accept ( node )  { 
16811718      if  ( node . getAttribute ( 'role' )  ===  'option' )  return  NodeFilter . FILTER_REJECT 
16821719      if  ( node . hasAttribute ( 'role' ) )  return  NodeFilter . FILTER_SKIP 
@@ -1687,7 +1724,7 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
16871724    } , 
16881725  } ) 
16891726
1690-   let  labelledBy  =  useLabelledBy ( [ data . buttonRef . current ?. id ] ) 
1727+   let  labelledBy  =  useLabelledBy ( [ data . buttonElement ?. id ] ) 
16911728
16921729  let  slot  =  useMemo ( ( )  =>  { 
16931730    return  { 
@@ -1728,8 +1765,8 @@ function OptionsFn<TTag extends ElementType = typeof DEFAULT_OPTIONS_TAG>(
17281765    style : { 
17291766      ...theirProps . style , 
17301767      ...style , 
1731-       '--input-width' : useElementSize ( data . inputRef ,  true ) . width , 
1732-       '--button-width' : useElementSize ( data . buttonRef ,  true ) . width , 
1768+       '--input-width' : useElementSize ( data . inputElement ,  true ) . width , 
1769+       '--button-width' : useElementSize ( data . buttonElement ,  true ) . width , 
17331770    }  as  CSSProperties , 
17341771    onWheel : data . activationTrigger  ===  ActivationTrigger . Pointer  ? undefined  : handleWheel , 
17351772    onMouseDown : handleMouseDown , 
@@ -1840,7 +1877,7 @@ function OptionFn<
18401877    ...theirProps 
18411878  }  =  props 
18421879
1843-   let  refocusInput  =  useRefocusableInput ( data . inputRef ) 
1880+   let  refocusInput  =  useRefocusableInput ( data . inputElement ) 
18441881
18451882  let  active  =  data . virtual 
18461883    ? data . activeOptionIndex  ===  data . calculateIndex ( value ) 
0 commit comments