@@ -21,7 +21,7 @@ import type { Placements } from '../../types'
21
21
import { getNextActiveElement , isRTL } from '../../utils'
22
22
23
23
import type { Alignments , Directions } from './types'
24
- import { getPlacement } from './utils'
24
+ import { getPlacement , getReferenceElement } from './utils'
25
25
import { CFocusTrap } from '../focus-trap'
26
26
27
27
export interface CDropdownProps extends HTMLAttributes < HTMLDivElement | HTMLLIElement > {
@@ -161,6 +161,27 @@ export interface CDropdownProps extends HTMLAttributes<HTMLDivElement | HTMLLIEl
161
161
*/
162
162
portal ?: boolean
163
163
164
+ /**
165
+ * Sets the reference element for positioning the React Dropdown Menu.
166
+ * - `toggle` - The React Dropdown Toggle button (default).
167
+ * - `parent` - The React Dropdown wrapper element.
168
+ * - `HTMLElement` - A custom HTML element.
169
+ * - `React.RefObject` - A custom reference element.
170
+ *
171
+ * @example
172
+ * // Use the parent element as reference for positioning
173
+ * <CDropdown reference="parent">
174
+ * <CDropdownToggle>Toggle dropdown</CDropdownToggle>
175
+ * <CDropdownMenu>
176
+ * <CDropdownItem>Action</CDropdownItem>
177
+ * <CDropdownItem>Another Action</CDropdownItem>
178
+ * </CDropdownMenu>
179
+ * </CDropdown>
180
+ *
181
+ * @since 5.9.0
182
+ */
183
+ reference ?: 'parent' | 'toggle' | HTMLElement | React . RefObject < HTMLElement | null >
184
+
164
185
/**
165
186
* Defines the visual variant of the React Dropdown
166
187
*/
@@ -204,6 +225,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
204
225
popper = true ,
205
226
popperConfig,
206
227
portal = false ,
228
+ reference = 'toggle' ,
207
229
variant = 'btn-group' ,
208
230
visible = false ,
209
231
...rest
@@ -255,12 +277,12 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
255
277
} , [ visible ] )
256
278
257
279
useEffect ( ( ) => {
258
- const toggleElement = dropdownToggleElement
280
+ const referenceElement = getReferenceElement ( reference , dropdownToggleElement , dropdownRef )
259
281
const menuElement = dropdownMenuRef . current
260
- if ( allowPopperUse && menuElement && toggleElement && _visible ) {
261
- initPopper ( toggleElement , menuElement , computedPopperConfig )
282
+ if ( allowPopperUse && menuElement && referenceElement && _visible ) {
283
+ initPopper ( referenceElement , menuElement , computedPopperConfig )
262
284
}
263
- } , [ dropdownToggleElement ] )
285
+ } , [ dropdownToggleElement , reference ] )
264
286
265
287
useEffect ( ( ) => {
266
288
if ( pendingKeyDownEvent !== null ) {
@@ -272,21 +294,21 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
272
294
const handleHide = useCallback ( ( ) => {
273
295
setVisible ( false )
274
296
275
- const toggleElement = dropdownToggleElement
276
297
const menuElement = dropdownMenuRef . current
298
+ const toggleElement = dropdownToggleElement
277
299
278
300
if ( allowPopperUse ) {
279
301
destroyPopper ( )
280
302
}
281
303
282
- toggleElement ?. removeEventListener ( 'keydown' , handleKeydown )
283
304
menuElement ?. removeEventListener ( 'keydown' , handleKeydown )
305
+ toggleElement ?. removeEventListener ( 'keydown' , handleKeydown )
284
306
285
307
window . removeEventListener ( 'click' , handleClick )
286
308
window . removeEventListener ( 'keyup' , handleKeyup )
287
309
288
310
onHide ?.( )
289
- } , [ dropdownToggleElement , allowPopperUse , destroyPopper , onHide ] )
311
+ } , [ allowPopperUse , dropdownToggleElement , destroyPopper , onHide ] )
290
312
291
313
const handleKeydown = useCallback ( ( event : KeyboardEvent ) => {
292
314
if ( ! dropdownMenuRef . current ) {
@@ -316,7 +338,7 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
316
338
dropdownToggleElement ?. focus ( )
317
339
}
318
340
} ,
319
- [ autoClose , handleHide ]
341
+ [ autoClose , dropdownToggleElement , handleHide ]
320
342
)
321
343
322
344
const handleClick = useCallback (
@@ -357,14 +379,15 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
357
379
358
380
const handleShow = useCallback (
359
381
( event ?: KeyboardEvent ) => {
360
- const toggleElement = dropdownToggleElement
361
382
const menuElement = dropdownMenuRef . current
383
+ const referenceElement = getReferenceElement ( reference , dropdownToggleElement , dropdownRef )
384
+ const toggleElement = dropdownToggleElement
362
385
363
- if ( toggleElement && menuElement ) {
386
+ if ( menuElement && referenceElement && toggleElement ) {
364
387
setVisible ( true )
365
388
366
389
if ( allowPopperUse ) {
367
- initPopper ( toggleElement , menuElement , computedPopperConfig )
390
+ initPopper ( referenceElement , menuElement , computedPopperConfig )
368
391
}
369
392
370
393
toggleElement . focus ( )
@@ -382,13 +405,14 @@ export const CDropdown: PolymorphicRefForwardingComponent<'div', CDropdownProps>
382
405
}
383
406
} ,
384
407
[
385
- dropdownToggleElement ,
386
408
allowPopperUse ,
387
- initPopper ,
388
409
computedPopperConfig ,
410
+ dropdownToggleElement ,
411
+ reference ,
389
412
handleClick ,
390
413
handleKeydown ,
391
414
handleKeyup ,
415
+ initPopper ,
392
416
onShow ,
393
417
]
394
418
)
0 commit comments