From ade8e16c8272dffd82db1b0e2d0ff43787a96c98 Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Mon, 27 Apr 2026 14:50:32 +0200 Subject: [PATCH 1/2] ui: Forward `style` and `className` from `*.Popup` to inner Base UI Popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `Popover.Popup`, `Tooltip.Popup`, and `Select.Popup` previously forwarded `style` and `className` to the outer Base UI `Positioner`. Now that the `portal` prop pattern lets consumers customize the wrapping `Portal` directly, the silent forwarding to `Positioner` is no longer needed and brings these wrappers in line with `Dialog.Popup`, `AlertDialog.Popup`, and `Drawer.Popup`, which already forward to the popup element. Z-index is still applied to the `Positioner` via the `--wp-ui--z-index` CSS variable, which can be set on a wrapping element or per-instance through ``. Made-with: Cursor --- packages/ui/CHANGELOG.md | 1 + packages/ui/src/form/primitives/select/popup.tsx | 7 +++---- packages/ui/src/form/primitives/select/types.ts | 11 +++++++++++ packages/ui/src/popover/popup.tsx | 13 ++++++------- packages/ui/src/popover/types.ts | 11 +++++++---- packages/ui/src/tooltip/popup.tsx | 10 +++------- packages/ui/src/tooltip/types.ts | 11 +++++++++++ 7 files changed, 42 insertions(+), 22 deletions(-) diff --git a/packages/ui/CHANGELOG.md b/packages/ui/CHANGELOG.md index ba9b97ca6e8855..31bf823f626ea2 100644 --- a/packages/ui/CHANGELOG.md +++ b/packages/ui/CHANGELOG.md @@ -5,6 +5,7 @@ ### Breaking Changes - `Dialog`, `AlertDialog`, `Popover`, `Tooltip`, `Select`: **`Popup` portal API** ([#77452](https://github.com/WordPress/gutenberg/pull/77452)). Add `Portal` subcomponents and an optional `portal` prop on `Popup` (when omitted, the default `Portal` is used). Remove `container` from every `Popup` and `portalClassName` from `Dialog.Popup` / `AlertDialog.Popup`; pass `portal={ }` for `container`, `className`, `style`, and other portal options. +- `Popover`, `Tooltip`, `Select`: `style` and `className` on `Popup` are now forwarded to the inner Base UI `Popup` element instead of the outer `Positioner`. To override the per-instance z-index, pass `portal={ -z-index': '9999' } } /> }` (or set the variable globally on a wrapping element); inline `style={ { zIndex: … } }` on `Popup` no longer reaches the positioned element. ### New Features diff --git a/packages/ui/src/form/primitives/select/popup.tsx b/packages/ui/src/form/primitives/select/popup.tsx index 8bd56eca3b51b6..431c3a18fd345f 100644 --- a/packages/ui/src/form/primitives/select/popup.tsx +++ b/packages/ui/src/form/primitives/select/popup.tsx @@ -26,17 +26,16 @@ export const Popup = forwardRef< HTMLDivElement, SelectPopupProps >( <_Select.Positioner { ...ITEM_POPUP_POSITIONER_PROPS } alignItemWithTrigger={ false } - style={ style } className={ clsx( resetStyles[ 'box-sizing' ], - styles.positioner, - className + styles.positioner ) } > <_Select.Popup ref={ ref } - className={ itemPopupStyles.popup } + style={ style } + className={ clsx( itemPopupStyles.popup, className ) } { ...restProps } > <_Select.List className={ itemPopupStyles.list }> diff --git a/packages/ui/src/form/primitives/select/types.ts b/packages/ui/src/form/primitives/select/types.ts index abfc3ef63281b5..c4bffb7534fbbf 100644 --- a/packages/ui/src/form/primitives/select/types.ts +++ b/packages/ui/src/form/primitives/select/types.ts @@ -32,6 +32,17 @@ export type SelectTriggerProps = ComponentProps< typeof _Select.Trigger > & { children?: _Select.Value.Props[ 'children' ]; }; +/** + * `Select.Popup` maps to two Base UI elements internally: the + * **Positioner** (outer, handles fixed positioning and z-index) and the + * **Popup** (inner, holds content and visual styles). + * + * `style`, `className`, and all other HTML attributes are forwarded to the + * inner **Popup** element. + * + * To override the z-index, use the `--wp-ui-select-z-index` CSS variable + * via `Select.Portal` (per-instance) or globally on a wrapping element. + */ export type SelectPopupProps = ComponentProps< typeof _Select.Popup > & { /** * The content to be rendered inside the popup. diff --git a/packages/ui/src/popover/popup.tsx b/packages/ui/src/popover/popup.tsx index 3c105bff1d45ff..2dab378e344511 100644 --- a/packages/ui/src/popover/popup.tsx +++ b/packages/ui/src/popover/popup.tsx @@ -75,19 +75,18 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function PopoverPopup( side={ side } sideOffset={ sideOffset } sticky={ sticky } - style={ style } - className={ clsx( - resetStyles[ 'box-sizing' ], - styles.positioner, - className - ) } + className={ clsx( resetStyles[ 'box-sizing' ], styles.positioner ) } > <_Popover.Popup ref={ mergedPopupRef } initialFocus={ resolvedInitialFocus } finalFocus={ finalFocus } - className={ clsx( variant !== 'unstyled' && styles.popup ) } + style={ style } + className={ clsx( + variant !== 'unstyled' && styles.popup, + className + ) } { ...props } > diff --git a/packages/ui/src/popover/types.ts b/packages/ui/src/popover/types.ts index 914504fcbf4ea7..1bc555aa7e6d92 100644 --- a/packages/ui/src/popover/types.ts +++ b/packages/ui/src/popover/types.ts @@ -30,10 +30,13 @@ export interface TriggerProps * **Positioner** (outer, handles fixed positioning and z-index) and the * **Popup** (inner, holds content and visual styles). * - * `style` and `className` are forwarded to the **Positioner** so that - * z-index overrides (`--wp-ui-popover-z-index`) and Base UI CSS variables - * (`--available-height`, `--available-width`) work correctly. All other - * HTML attributes are forwarded to the inner **Popup** element. + * `style`, `className`, and all other HTML attributes are forwarded to the + * inner **Popup** element. Base UI CSS variables exposed by the positioner + * (`--available-height`, `--available-width`, `--anchor-width`, etc.) + * cascade down and remain readable from the popup. + * + * To override the z-index, use the `--wp-ui-popover-z-index` CSS variable + * via `Popover.Portal` (per-instance) or globally on a wrapping element. */ export interface PopupProps extends ComponentProps< 'div' >, diff --git a/packages/ui/src/tooltip/popup.tsx b/packages/ui/src/tooltip/popup.tsx index ddc31efba1a9b4..939f3d75f1bb9b 100644 --- a/packages/ui/src/tooltip/popup.tsx +++ b/packages/ui/src/tooltip/popup.tsx @@ -33,12 +33,7 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function TooltipPopup( align={ align } side={ side } sideOffset={ sideOffset } - style={ style } - className={ clsx( - resetStyles[ 'box-sizing' ], - className, - styles.positioner - ) } + className={ clsx( resetStyles[ 'box-sizing' ], styles.positioner ) } > { /* This should ideally use whatever dark color makes sense, and not be hardcoded to #1e1e1e. The solutions would be to: @@ -52,7 +47,8 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function TooltipPopup( <_Tooltip.Popup ref={ ref } - className={ styles.popup } + style={ style } + className={ clsx( styles.popup, className ) } { ...props } > { children } diff --git a/packages/ui/src/tooltip/types.ts b/packages/ui/src/tooltip/types.ts index e68a6a7a0aaf31..287c9a2ae855de 100644 --- a/packages/ui/src/tooltip/types.ts +++ b/packages/ui/src/tooltip/types.ts @@ -19,6 +19,17 @@ export interface TriggerProps extends ComponentProps< 'button' > { children?: ReactNode; } +/** + * `Tooltip.Popup` maps to two Base UI elements internally: the + * **Positioner** (outer, handles fixed positioning and z-index) and the + * **Popup** (inner, holds content and visual styles). + * + * `style`, `className`, and all other HTML attributes are forwarded to the + * inner **Popup** element. + * + * To override the z-index, use the `--wp-ui-tooltip-z-index` CSS variable + * via `Tooltip.Portal` (per-instance) or globally on a wrapping element. + */ export interface PopupProps extends ComponentProps< 'div' >, Pick< _Tooltip.Positioner.Props, 'align' | 'side' | 'sideOffset' > { From d552782fe4bf4b0db7e80e9421f47cfc8b826f1f Mon Sep 17 00:00:00 2001 From: Marco Ciampini Date: Mon, 27 Apr 2026 15:35:40 +0200 Subject: [PATCH 2/2] ui: Drop redundant `*.PopupProps` JSDoc and forward `style` implicitly After the previous commit aligned `Popover.Popup`, `Tooltip.Popup`, and `Select.Popup` with their silent siblings (`Dialog`, `AlertDialog`, `Drawer`), the JSDoc blocks added to the three `PopupProps` types only documented behavior that is no longer surprising. The sibling overlays carry no such doc block, and the z-index escape hatch is now documented uniformly via the Storybook stories aligned in #77648. Also let `style` flow to the inner Base UI `Popup` implicitly via `...props` instead of destructuring it just to re-pass it unchanged. Made-with: Cursor --- packages/ui/src/form/primitives/select/popup.tsx | 6 +----- packages/ui/src/form/primitives/select/types.ts | 11 ----------- packages/ui/src/popover/popup.tsx | 2 -- packages/ui/src/popover/types.ts | 13 ------------- packages/ui/src/tooltip/popup.tsx | 2 -- packages/ui/src/tooltip/types.ts | 11 ----------- 6 files changed, 1 insertion(+), 44 deletions(-) diff --git a/packages/ui/src/form/primitives/select/popup.tsx b/packages/ui/src/form/primitives/select/popup.tsx index 431c3a18fd345f..bae67abb1bd1ec 100644 --- a/packages/ui/src/form/primitives/select/popup.tsx +++ b/packages/ui/src/form/primitives/select/popup.tsx @@ -18,10 +18,7 @@ const ThemeProvider: typeof ThemeProviderType = unlock( themePrivateApis ).ThemeProvider; export const Popup = forwardRef< HTMLDivElement, SelectPopupProps >( - function Popup( - { className, portal, children, style, ...restProps }, - ref - ) { + function Popup( { className, portal, children, ...restProps }, ref ) { const portalChildren = ( <_Select.Positioner { ...ITEM_POPUP_POSITIONER_PROPS } @@ -34,7 +31,6 @@ export const Popup = forwardRef< HTMLDivElement, SelectPopupProps >( <_Select.Popup ref={ ref } - style={ style } className={ clsx( itemPopupStyles.popup, className ) } { ...restProps } > diff --git a/packages/ui/src/form/primitives/select/types.ts b/packages/ui/src/form/primitives/select/types.ts index c4bffb7534fbbf..abfc3ef63281b5 100644 --- a/packages/ui/src/form/primitives/select/types.ts +++ b/packages/ui/src/form/primitives/select/types.ts @@ -32,17 +32,6 @@ export type SelectTriggerProps = ComponentProps< typeof _Select.Trigger > & { children?: _Select.Value.Props[ 'children' ]; }; -/** - * `Select.Popup` maps to two Base UI elements internally: the - * **Positioner** (outer, handles fixed positioning and z-index) and the - * **Popup** (inner, holds content and visual styles). - * - * `style`, `className`, and all other HTML attributes are forwarded to the - * inner **Popup** element. - * - * To override the z-index, use the `--wp-ui-select-z-index` CSS variable - * via `Select.Portal` (per-instance) or globally on a wrapping element. - */ export type SelectPopupProps = ComponentProps< typeof _Select.Popup > & { /** * The content to be rendered inside the popup. diff --git a/packages/ui/src/popover/popup.tsx b/packages/ui/src/popover/popup.tsx index 2dab378e344511..52eb7c6e6494f0 100644 --- a/packages/ui/src/popover/popup.tsx +++ b/packages/ui/src/popover/popup.tsx @@ -47,7 +47,6 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function PopoverPopup( side = 'bottom', sideOffset = 8, sticky, - style, variant = 'default', ...props }, @@ -82,7 +81,6 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function PopoverPopup( ref={ mergedPopupRef } initialFocus={ resolvedInitialFocus } finalFocus={ finalFocus } - style={ style } className={ clsx( variant !== 'unstyled' && styles.popup, className diff --git a/packages/ui/src/popover/types.ts b/packages/ui/src/popover/types.ts index 1bc555aa7e6d92..fb5315f4f12e1c 100644 --- a/packages/ui/src/popover/types.ts +++ b/packages/ui/src/popover/types.ts @@ -25,19 +25,6 @@ export interface TriggerProps children?: ReactNode; } -/** - * `Popover.Popup` maps to two Base UI elements internally: the - * **Positioner** (outer, handles fixed positioning and z-index) and the - * **Popup** (inner, holds content and visual styles). - * - * `style`, `className`, and all other HTML attributes are forwarded to the - * inner **Popup** element. Base UI CSS variables exposed by the positioner - * (`--available-height`, `--available-width`, `--anchor-width`, etc.) - * cascade down and remain readable from the popup. - * - * To override the z-index, use the `--wp-ui-popover-z-index` CSS variable - * via `Popover.Portal` (per-instance) or globally on a wrapping element. - */ export interface PopupProps extends ComponentProps< 'div' >, Pick< diff --git a/packages/ui/src/tooltip/popup.tsx b/packages/ui/src/tooltip/popup.tsx index 939f3d75f1bb9b..34581f0d572a05 100644 --- a/packages/ui/src/tooltip/popup.tsx +++ b/packages/ui/src/tooltip/popup.tsx @@ -23,7 +23,6 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function TooltipPopup( sideOffset = 4, children, className, - style, ...props }, ref @@ -47,7 +46,6 @@ const Popup = forwardRef< HTMLDivElement, PopupProps >( function TooltipPopup( <_Tooltip.Popup ref={ ref } - style={ style } className={ clsx( styles.popup, className ) } { ...props } > diff --git a/packages/ui/src/tooltip/types.ts b/packages/ui/src/tooltip/types.ts index 287c9a2ae855de..e68a6a7a0aaf31 100644 --- a/packages/ui/src/tooltip/types.ts +++ b/packages/ui/src/tooltip/types.ts @@ -19,17 +19,6 @@ export interface TriggerProps extends ComponentProps< 'button' > { children?: ReactNode; } -/** - * `Tooltip.Popup` maps to two Base UI elements internally: the - * **Positioner** (outer, handles fixed positioning and z-index) and the - * **Popup** (inner, holds content and visual styles). - * - * `style`, `className`, and all other HTML attributes are forwarded to the - * inner **Popup** element. - * - * To override the z-index, use the `--wp-ui-tooltip-z-index` CSS variable - * via `Tooltip.Portal` (per-instance) or globally on a wrapping element. - */ export interface PopupProps extends ComponentProps< 'div' >, Pick< _Tooltip.Positioner.Props, 'align' | 'side' | 'sideOffset' > {