@@ -67,6 +67,7 @@ type ComboboxOptionDataRef<T> = MutableRefObject<{
67
67
68
68
interface StateDefinition < T > {
69
69
dataRef : MutableRefObject < _Data >
70
+ labelId : string | null
70
71
71
72
comboboxState : ComboboxState
72
73
@@ -83,6 +84,8 @@ enum ActionTypes {
83
84
84
85
RegisterOption ,
85
86
UnregisterOption ,
87
+
88
+ RegisterLabel ,
86
89
}
87
90
88
91
function adjustOrderedState < T > (
@@ -124,6 +127,7 @@ type Actions<T> =
124
127
trigger ?: ActivationTrigger
125
128
}
126
129
| { type : ActionTypes . RegisterOption ; id : string ; dataRef : ComboboxOptionDataRef < T > }
130
+ | { type : ActionTypes . RegisterLabel ; id : string | null }
127
131
| { type : ActionTypes . UnregisterOption ; id : string }
128
132
129
133
let reducers : {
@@ -227,12 +231,19 @@ let reducers: {
227
231
activationTrigger : ActivationTrigger . Other ,
228
232
}
229
233
} ,
234
+ [ ActionTypes . RegisterLabel ] : ( state , action ) => {
235
+ return {
236
+ ...state ,
237
+ labelId : action . id ,
238
+ }
239
+ } ,
230
240
}
231
241
232
242
let ComboboxActionsContext = createContext < {
233
243
openCombobox ( ) : void
234
244
closeCombobox ( ) : void
235
245
registerOption ( id : string , dataRef : ComboboxOptionDataRef < unknown > ) : ( ) => void
246
+ registerLabel ( id : string ) : ( ) => void
236
247
goToOption ( focus : Focus . Specific , id : string , trigger ?: ActivationTrigger ) : void
237
248
goToOption ( focus : Focus , id ?: string , trigger ?: ActivationTrigger ) : void
238
249
selectOption ( id : string ) : void
@@ -402,6 +413,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
402
413
options : [ ] ,
403
414
activeOptionIndex : null ,
404
415
activationTrigger : ActivationTrigger . Other ,
416
+ labelId : null ,
405
417
} as StateDefinition < TValue > )
406
418
407
419
let defaultToFirstOption = useRef ( false )
@@ -536,6 +548,11 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
536
548
return ( ) => dispatch ( { type : ActionTypes . UnregisterOption , id } )
537
549
} )
538
550
551
+ let registerLabel = useEvent ( ( id ) => {
552
+ dispatch ( { type : ActionTypes . RegisterLabel , id } )
553
+ return ( ) => dispatch ( { type : ActionTypes . RegisterLabel , id : null } )
554
+ } )
555
+
539
556
let onChange = useEvent ( ( value : unknown ) => {
540
557
return match ( data . mode , {
541
558
[ ValueMode . Single ] ( ) {
@@ -560,6 +577,7 @@ function ComboboxFn<TValue, TTag extends ElementType = typeof DEFAULT_COMBOBOX_T
560
577
( ) => ( {
561
578
onChange,
562
579
registerOption,
580
+ registerLabel,
563
581
goToOption,
564
582
closeCombobox,
565
583
openCombobox,
@@ -775,9 +793,9 @@ let Input = forwardRefWithAs(function Input<
775
793
// TODO: Verify this. The spec says that, for the input/combobox, the label is the labelling element when present
776
794
// Otherwise it's the ID of the non-label element
777
795
let labelledby = useComputed ( ( ) => {
778
- if ( ! data . labelRef . current ) return undefined
779
- return [ data . labelRef . current . id ] . join ( ' ' )
780
- } , [ data . labelRef . current ] )
796
+ if ( ! data . labelId ) return undefined
797
+ return [ data . labelId ] . join ( ' ' )
798
+ } , [ data . labelId ] )
781
799
782
800
let slot = useMemo < InputRenderPropArg > (
783
801
( ) => ( { open : data . comboboxState === ComboboxState . Open , disabled : data . disabled } ) ,
@@ -892,9 +910,9 @@ let Button = forwardRefWithAs(function Button<TTag extends ElementType = typeof
892
910
} )
893
911
894
912
let labelledby = useComputed ( ( ) => {
895
- if ( ! data . labelRef . current ) return undefined
896
- return [ data . labelRef . current . id , id ] . join ( ' ' )
897
- } , [ data . labelRef . current , id ] )
913
+ if ( ! data . labelId ) return undefined
914
+ return [ data . labelId , id ] . join ( ' ' )
915
+ } , [ data . labelId , id ] )
898
916
899
917
let slot = useMemo < ButtonRenderPropArg > (
900
918
( ) => ( {
@@ -943,8 +961,11 @@ let Label = forwardRefWithAs(function Label<TTag extends ElementType = typeof DE
943
961
) {
944
962
let data = useData ( 'Combobox.Label' )
945
963
let id = `headlessui-combobox-label-${ useId ( ) } `
964
+ let actions = useActions ( 'Combobox.Label' )
946
965
let labelRef = useSyncRefs ( data . labelRef , ref )
947
966
967
+ useIsoMorphicEffect ( ( ) => actions . registerLabel ( id ) , [ id ] )
968
+
948
969
let handleClick = useEvent ( ( ) => data . inputRef . current ?. focus ( { preventScroll : true } ) )
949
970
950
971
let slot = useMemo < LabelRenderPropArg > (
@@ -1027,8 +1048,8 @@ let Options = forwardRefWithAs(function Options<
1027
1048
} )
1028
1049
1029
1050
let labelledby = useComputed (
1030
- ( ) => data . labelRef . current ?. id ?? data . buttonRef . current ?. id ,
1031
- [ data . labelRef . current , data . buttonRef . current ]
1051
+ ( ) => data . labelId ?? data . buttonRef . current ?. id ,
1052
+ [ data . labelId , data . buttonRef . current ]
1032
1053
)
1033
1054
1034
1055
let slot = useMemo < OptionsRenderPropArg > (
0 commit comments