diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 9a245d85ebf849..a21e0f23334e1a 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -10,9 +10,10 @@
- `PaletteEdit` and `CircularOptionPicker`: improve unit tests ([#57809](https://github.com/WordPress/gutenberg/pull/57809)).
- `Tooltip`: no-op when nested inside other `Tooltip` components ([#57202](https://github.com/WordPress/gutenberg/pull/57202)).
-### Bug Fixes
+### Bug Fix
- `ToggleGroupControl`: Improve controlled value detection ([#57770](https://github.com/WordPress/gutenberg/pull/57770)).
+- `Tooltip`: Improve props forwarding to children of nested `Tooltip` components ([#57878](https://github.com/WordPress/gutenberg/pull/57878)).
### Experimental
diff --git a/packages/components/src/tooltip/index.tsx b/packages/components/src/tooltip/index.tsx
index 1e652d9a42dbb4..f71182b85edb2c 100644
--- a/packages/components/src/tooltip/index.tsx
+++ b/packages/components/src/tooltip/index.tsx
@@ -8,34 +8,39 @@ import * as Ariakit from '@ariakit/react';
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';
-import { Children, cloneElement } from '@wordpress/element';
+import {
+ Children,
+ useContext,
+ createContext,
+ forwardRef,
+} from '@wordpress/element';
import deprecated from '@wordpress/deprecated';
/**
* Internal dependencies
*/
-import type { TooltipProps, TooltipInternalContext } from './types';
+import type {
+ TooltipProps,
+ TooltipInternalContext as TooltipInternalContextType,
+} from './types';
import Shortcut from '../shortcut';
import { positionToPlacement } from '../popover/utils';
-import {
- contextConnect,
- useContextSystem,
- ContextSystemProvider,
-} from '../context';
import type { WordPressComponentProps } from '../context';
+const TooltipInternalContext = createContext< TooltipInternalContextType >( {
+ isNestedInTooltip: false,
+} );
+
/**
* Time over anchor to wait before showing tooltip
*/
export const TOOLTIP_DELAY = 700;
const CONTEXT_VALUE = {
- Tooltip: {
- isNestedInTooltip: true,
- },
+ isNestedInTooltip: true,
};
-function UnconnectedTooltip(
+function UnforwardedTooltip(
props: WordPressComponentProps< TooltipProps, 'div', false >,
ref: React.ForwardedRef< any >
) {
@@ -48,14 +53,10 @@ function UnconnectedTooltip(
shortcut,
text,
- // From Internal Context system
- isNestedInTooltip,
-
...restProps
- } = useContextSystem< typeof props & TooltipInternalContext >(
- props,
- 'Tooltip'
- );
+ } = props;
+
+ const { isNestedInTooltip } = useContext( TooltipInternalContext );
const baseId = useInstanceId( Tooltip, 'tooltip' );
const describedById = text || shortcut ? baseId : undefined;
@@ -96,16 +97,15 @@ function UnconnectedTooltip(
} );
if ( isNestedInTooltip ) {
- return isOnlyChild
- ? cloneElement( children, {
- ...restProps,
- ref,
- } )
- : children;
+ return isOnlyChild ? (
+
+ ) : (
+ children
+ );
}
return (
-
+
) }
-
+
);
}
-export const Tooltip = contextConnect( UnconnectedTooltip, 'Tooltip' );
+export const Tooltip = forwardRef( UnforwardedTooltip );
export default Tooltip;
diff --git a/packages/components/src/tooltip/test/index.tsx b/packages/components/src/tooltip/test/index.tsx
index ed6f7b5f7b4a14..40038bbc5e25ad 100644
--- a/packages/components/src/tooltip/test/index.tsx
+++ b/packages/components/src/tooltip/test/index.tsx
@@ -102,6 +102,17 @@ describe( 'Tooltip', () => {
screen.queryByRole( 'button', { description: 'tooltip text' } )
).not.toBeInTheDocument();
} );
+
+ it( 'should not leak Tooltip props to the tooltip anchor', () => {
+ render(
+
+
+
+ );
+ expect(
+ screen.getByRole( 'button', { name: 'Anchor' } )
+ ).not.toHaveAttribute( 'data-foo' );
+ } );
} );
describe( 'keyboard focus', () => {
diff --git a/packages/components/src/tooltip/types.ts b/packages/components/src/tooltip/types.ts
index 3d28a1a0e96c67..11268683bc2ced 100644
--- a/packages/components/src/tooltip/types.ts
+++ b/packages/components/src/tooltip/types.ts
@@ -61,5 +61,5 @@ export type TooltipProps = {
};
export type TooltipInternalContext = {
- isNestedInTooltip?: boolean;
+ isNestedInTooltip: boolean;
};