diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 0e8026b8115aad..b5b52985043fe2 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -18,6 +18,7 @@
### Bug Fix
+- CustomSelectControl: Update to use a Popover component for rendering the menu ([#37272](https://github.com/WordPress/gutenberg/pull/37272)).
- Fixed spacing between `BaseControl` fields and help text within the `ToolsPanel` ([#36334](https://github.com/WordPress/gutenberg/pull/36334))
- Replaced hardcoded blue in `ColorPicker` with UI theme color ([#36153](https://github.com/WordPress/gutenberg/pull/36153)).
- Fixed empty `ToolsPanel` height by correcting menu button line-height ([#36895](https://github.com/WordPress/gutenberg/pull/36895)).
diff --git a/packages/components/src/custom-select-control/index.js b/packages/components/src/custom-select-control/index.js
index 90b5bbf2115e20..8c2ca45ad86c4d 100644
--- a/packages/components/src/custom-select-control/index.js
+++ b/packages/components/src/custom-select-control/index.js
@@ -7,12 +7,32 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
+import { useResizeObserver } from '@wordpress/compose';
+import { useRef } from '@wordpress/element';
import { Icon, check, chevronDown } from '@wordpress/icons';
import { __, sprintf } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import { Button, VisuallyHidden } from '../';
+import { Button, Popover, VisuallyHidden } from '../';
+
+const OptionList = ( { anchorRef, isOpen, children } ) => {
+ if ( ! isOpen ) {
+ return children;
+ }
+
+ return (
+
+ { children }
+
+ );
+};
const itemToString = ( item ) => item?.name;
// This is needed so that in Windows, where
@@ -81,6 +101,14 @@ export default function CustomSelectControl( {
stateReducer,
} );
+ const anchorRef = useRef();
+
+ // Calculate Popover width based on the size of the component's container.
+ const [
+ containerResizeListener,
+ { width: containerWidth },
+ ] = useResizeObserver();
+
function getDescribedBy() {
if ( describedBy ) {
return describedBy;
@@ -97,20 +125,36 @@ export default function CustomSelectControl( {
const menuProps = getMenuProps( {
className: 'components-custom-select-control__menu',
'aria-hidden': ! isOpen,
+ style: {
+ width: containerWidth,
+ },
} );
+
// We need this here, because the null active descendant is not fully ARIA compliant.
if (
menuProps[ 'aria-activedescendant' ]?.startsWith( 'downshift-null' )
) {
delete menuProps[ 'aria-activedescendant' ];
}
+
+ const toggleButtonProps = getToggleButtonProps( {
+ // This is needed because some speech recognition software don't support `aria-labelledby`.
+ 'aria-label': label,
+ 'aria-labelledby': undefined,
+ className: 'components-custom-select-control__button',
+ isSmall: true,
+ describedBy: getDescribedBy(),
+ } );
+
return (
+ { containerResizeListener }
{ hideLabelFromVision ? (
{ label }
@@ -125,58 +169,51 @@ export default function CustomSelectControl( {
{ label }
) }
-
);
}
diff --git a/packages/components/src/custom-select-control/style.scss b/packages/components/src/custom-select-control/style.scss
index f3175331336bfd..5499827c1094dc 100644
--- a/packages/components/src/custom-select-control/style.scss
+++ b/packages/components/src/custom-select-control/style.scss
@@ -41,18 +41,12 @@
display: none;
}
- // Block UI appearance.
- border: $border-width solid $gray-900;
- background-color: $white;
- border-radius: $radius-block-ui;
outline: none;
transition: none;
-
max-height: 400px;
- min-width: 100%;
overflow: auto;
padding: 0;
- position: absolute;
+ margin: 0 (-$border-width); // Allow width value to include the Popover border width.
z-index: z-index(".components-popover");
}
@@ -84,3 +78,13 @@
margin-bottom: 0;
}
}
+
+.components-custom-select-control__popover {
+ &.components-popover {
+ .components-popover__content {
+ // Prevent the Popover scrollbars so that
+ // the scrollbars are only handled by the Menu.
+ overflow: hidden;
+ }
+ }
+}