Bug report
Current behavior
PopperAnchor has a useEffect with no dependency array that calls context.onAnchorChange() (which is setState) on every render:
React.useEffect(() => {
context.onAnchorChange(virtualRef?.current || ref.current);
}); // ← no dependency array
When a page has 50+ Radix components that use Popper internally (Tooltip, Popover, DropdownMenu, HoverCard), each PopperAnchor calls setState during the passive effects phase on mount. React counts all of these against a single 50-update limit per commit cycle, causing:
Error: Maximum update depth exceeded. This can happen when a component
repeatedly calls setState inside componentWillUpdate or componentDidUpdate.
React limits the number of nested updates to prevent infinite loops.
This is not an infinite loop — it's a cumulative depth issue from too many independent Popper instances mounting simultaneously. React Strict Mode (which double-invokes effects) makes this worse in development.
Expected behavior
PopperAnchor should not contribute to React's nested update depth counter on mount. The anchor element only needs to be set once when the DOM node is attached.
Proposed fix
Replace the dependency-less useEffect + setState with a callback ref:
const callbackRef = React.useCallback((node) => {
ref.current = node;
if (node) context.onAnchorChange(node);
}, [context.onAnchorChange]);
const composedRefs = useComposedRefs(forwardedRef, virtualRef ? ref : callbackRef);
React.useEffect(() => {
if (virtualRef?.current) context.onAnchorChange(virtualRef.current);
}, [virtualRef, context.onAnchorChange]);
React calls callback refs during DOM attachment in the commit phase, which does not count toward the nested update limit. The useEffect is kept only for the virtualRef case.
We verified this fix works via a pnpm patch on @radix-ui/react-popper@1.2.7.
Reproduction
Any page with 50+ Radix Tooltip/Popover/DropdownMenu/HoverCard components mounting in a single render pass. In our case: a workbench page with a sidebar nav (~10 items with Tooltips), action buttons with Tooltips (~15), and an inline document editor with citation HoverCards (~30+).
Environment
@radix-ui/react-popper: 1.2.7
- React 19.2.3
- Verified in both development (StrictMode) and production builds
Your minimal, reproducible example
Mount 60 Radix Tooltip components in a single page. Observe "Maximum update depth exceeded" on initial render.
Relevant package versions
@radix-ui/react-tooltip: 1.2.7
@radix-ui/react-popper: 1.2.7
react: 19.2.3
react-dom: 19.2.3
Bug report
Current behavior
PopperAnchorhas auseEffectwith no dependency array that callscontext.onAnchorChange()(which issetState) on every render:When a page has 50+ Radix components that use Popper internally (Tooltip, Popover, DropdownMenu, HoverCard), each
PopperAnchorcallssetStateduring the passive effects phase on mount. React counts all of these against a single 50-update limit per commit cycle, causing:This is not an infinite loop — it's a cumulative depth issue from too many independent Popper instances mounting simultaneously. React Strict Mode (which double-invokes effects) makes this worse in development.
Expected behavior
PopperAnchorshould not contribute to React's nested update depth counter on mount. The anchor element only needs to be set once when the DOM node is attached.Proposed fix
Replace the dependency-less
useEffect+setStatewith a callback ref:React calls callback refs during DOM attachment in the commit phase, which does not count toward the nested update limit. The
useEffectis kept only for thevirtualRefcase.We verified this fix works via a
pnpm patchon@radix-ui/react-popper@1.2.7.Reproduction
Any page with 50+ Radix Tooltip/Popover/DropdownMenu/HoverCard components mounting in a single render pass. In our case: a workbench page with a sidebar nav (~10 items with Tooltips), action buttons with Tooltips (~15), and an inline document editor with citation HoverCards (~30+).
Environment
@radix-ui/react-popper: 1.2.7Your minimal, reproducible example
Mount 60 Radix Tooltip components in a single page. Observe "Maximum update depth exceeded" on initial render.
Relevant package versions
@radix-ui/react-tooltip: 1.2.7@radix-ui/react-popper: 1.2.7react: 19.2.3react-dom: 19.2.3