@@ -105,7 +105,7 @@ const Dropdown = (props: DropdownProps) => {
105105 DetailedDropdownOption [ ]
106106 > ( [ ] ) ;
107107 const persistentOptions = useRef < DropdownProps [ 'options' ] > ( [ ] ) ;
108- const dropdownContainerRef = useRef < HTMLDivElement > ( null ) ;
108+ const dropdownContainerRef = useRef < HTMLButtonElement > ( null ) ;
109109
110110 const ctx = window . dash_component_api . useDashContext ( ) ;
111111 const loading = ctx . useLoading ( ) ;
@@ -428,26 +428,26 @@ const Dropdown = (props: DropdownProps) => {
428428 ) ;
429429
430430 return (
431- < div
432- id = { id }
433- ref = { dropdownContainerRef }
434- className = { `dash-dropdown ${ className ?? '' } ` }
435- style = { style }
436- data-dash-is-loading = { loading || undefined }
437- >
438- < Popover . Root open = { isOpen } onOpenChange = { handleOpenChange } >
439- < Popover . Trigger asChild >
440- < button
441- className = "dash-dropdown-grid-container dash-dropdown-trigger"
442- aria-label = { props . placeholder }
443- disabled = { disabled }
444- type = "button"
445- onKeyDown = { e => {
446- if ( e . key === 'ArrowDown' ) {
447- setIsOpen ( true ) ;
448- }
449- } }
450- >
431+ < Popover . Root open = { isOpen } onOpenChange = { handleOpenChange } >
432+ < Popover . Trigger asChild >
433+ < button
434+ id = { id }
435+ ref = { dropdownContainerRef }
436+ disabled = { disabled }
437+ type = "button"
438+ onKeyDown = { e => {
439+ if ( e . key === 'ArrowDown' ) {
440+ setIsOpen ( true ) ;
441+ }
442+ } }
443+ className = { `dash-dropdown ${ className ?? '' } ` }
444+ style = { style }
445+ aria-label = { props . placeholder }
446+ aria-haspopup = "listbox"
447+ aria-expanded = { isOpen }
448+ data-dash-is-loading = { loading || undefined }
449+ >
450+ < span className = "dash-dropdown-grid-container dash-dropdown-trigger" >
451451 { displayValue . length > 0 && (
452452 < span className = "dash-dropdown-value" >
453453 { displayValue }
@@ -481,100 +481,101 @@ const Dropdown = (props: DropdownProps) => {
481481 ) }
482482
483483 < CaretDownIcon className = "dash-dropdown-trigger-icon" />
484- </ button >
485- </ Popover . Trigger >
486-
487- < Popover . Portal container = { dropdownContainerRef . current } >
488- < Popover . Content
489- className = "dash-dropdown-content"
490- align = "start"
491- sideOffset = { 5 }
492- onOpenAutoFocus = { e => e . preventDefault ( ) }
493- onKeyDown = { handleKeyDown }
494- style = { {
495- maxHeight : maxHeight ? `${ maxHeight } px` : 'auto' ,
496- } }
497- >
498- { searchable && (
499- < div className = "dash-dropdown-grid-container dash-dropdown-search-container" >
500- < MagnifyingGlassIcon className = "dash-dropdown-search-icon" />
501- < input
502- type = "search"
503- className = "dash-dropdown-search"
504- placeholder = { localizations ?. search }
505- value = { search_value || '' }
506- autoComplete = "off"
507- onChange = { e =>
508- onInputChange ( e . target . value )
509- }
510- autoFocus
511- />
512- { search_value && (
513- < button
514- type = "button"
515- className = "dash-dropdown-clear"
516- onClick = { handleClearSearch }
517- aria-label = { localizations ?. clear_search }
518- >
519- < Cross1Icon />
520- </ button >
521- ) }
522- </ div >
523- ) }
524- { multi && (
525- < div className = "dash-dropdown-actions" >
484+ </ span >
485+ </ button >
486+ </ Popover . Trigger >
487+
488+ < Popover . Portal container = { dropdownContainerRef . current } >
489+ < Popover . Content
490+ className = "dash-dropdown-content"
491+ align = "start"
492+ sideOffset = { 5 }
493+ onOpenAutoFocus = { e => e . preventDefault ( ) }
494+ onKeyDown = { handleKeyDown }
495+ style = { {
496+ maxHeight : maxHeight ? `${ maxHeight } px` : 'auto' ,
497+ } }
498+ >
499+ { searchable && (
500+ < div className = "dash-dropdown-grid-container dash-dropdown-search-container" >
501+ < MagnifyingGlassIcon className = "dash-dropdown-search-icon" />
502+ < input
503+ type = "search"
504+ className = "dash-dropdown-search"
505+ placeholder = { localizations ?. search }
506+ value = { search_value || '' }
507+ autoComplete = "off"
508+ onChange = { e => onInputChange ( e . target . value ) }
509+ autoFocus
510+ />
511+ { search_value && (
512+ < button
513+ type = "button"
514+ className = "dash-dropdown-clear"
515+ onClick = { handleClearSearch }
516+ aria-label = { localizations ?. clear_search }
517+ >
518+ < Cross1Icon />
519+ </ button >
520+ ) }
521+ </ div >
522+ ) }
523+ { multi && (
524+ < div className = "dash-dropdown-actions" >
525+ < button
526+ type = "button"
527+ className = "dash-dropdown-action-button"
528+ onClick = { handleSelectAll }
529+ >
530+ { localizations ?. select_all }
531+ </ button >
532+ { canDeselectAll && (
526533 < button
527534 type = "button"
528535 className = "dash-dropdown-action-button"
529- onClick = { handleSelectAll }
536+ onClick = { handleDeselectAll }
530537 >
531- { localizations ?. select_all }
538+ { localizations ?. deselect_all }
532539 </ button >
533- { canDeselectAll && (
534- < button
535- type = "button"
536- className = "dash-dropdown-action-button"
537- onClick = { handleDeselectAll }
538- >
539- { localizations ?. deselect_all }
540- </ button >
541- ) }
542- </ div >
543- ) }
544- { isOpen && (
545- < div className = "dash-dropdown-options" >
546- { displayOptions . map ( ( option , i ) => {
547- const isSelected = multi
548- ? sanitizedValues . includes ( option . value )
549- : value === option . value ;
550-
551- return (
552- < DropdownOption
553- key = { `${ option . value } -${ i } ` }
554- index = { i }
555- option = { option }
556- isSelected = { isSelected }
557- onClick = { handleOptionClick }
558- style = { {
559- height : optionHeight
560- ? `${ optionHeight } px`
561- : undefined ,
562- } }
563- />
564- ) ;
565- } ) }
566- { search_value &&
567- displayOptions . length === 0 && (
568- < span className = "dash-dropdown-option" >
569- { localizations ?. no_options_found }
570- </ span >
571- ) }
572- </ div >
573- ) }
574- </ Popover . Content >
575- </ Popover . Portal >
576- </ Popover . Root >
577- </ div >
540+ ) }
541+ </ div >
542+ ) }
543+ { isOpen && (
544+ < div
545+ className = "dash-dropdown-options"
546+ role = "listbox"
547+ aria-multiselectable = { multi }
548+ >
549+ { displayOptions . map ( ( option , i ) => {
550+ const isSelected = multi
551+ ? sanitizedValues . includes ( option . value )
552+ : value === option . value ;
553+
554+ return (
555+ < DropdownOption
556+ key = { `${ option . value } -${ i } ` }
557+ index = { i }
558+ option = { option }
559+ isSelected = { isSelected }
560+ onClick = { handleOptionClick }
561+ style = { {
562+ height : optionHeight
563+ ? `${ optionHeight } px`
564+ : undefined ,
565+ } }
566+ />
567+ ) ;
568+ } ) }
569+ { search_value && displayOptions . length === 0 && (
570+ < span className = "dash-dropdown-option" >
571+ { localizations ?. no_options_found }
572+ </ span >
573+ ) }
574+ </ div >
575+ ) }
576+ </ Popover . Content >
577+ </ Popover . Portal >
578+ </ Popover . Root >
578579 ) ;
579580} ;
580581
0 commit comments