Skip to content

fix(components): Fix automcomplete crashing on resize larger [JOB-151844]#2924

Open
Aiden-Brine wants to merge 3 commits intomasterfrom
JOB-151844/max-depth-error
Open

fix(components): Fix automcomplete crashing on resize larger [JOB-151844]#2924
Aiden-Brine wants to merge 3 commits intomasterfrom
JOB-151844/max-depth-error

Conversation

@Aiden-Brine
Copy link
Contributor

@Aiden-Brine Aiden-Brine commented Feb 23, 2026

Motivations

Maximum depth errors popped up in DataDog related to Autocomplete. It was very difficult to re-create but we eventually figured out it could be recreated sometimes, for certain people, with a monitor connected, if they had the autocomplete menu open, and they expanded their screen size from smaller to larger. Here is a stack trace:

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.
    at getRootForUpdatedFiber (http://localhost:6007/node_modules/.cache/storybook/b124b7c47095b41d5ea618f285d096b0b3bcf3b8444e7fa72f6a80c348532f13/sb-vite/deps/chunk-HWACSCKG.js?v=2a05bdab:3001:128)
    at enqueueConcurrentHookUpdate (http://localhost:6007/node_modules/.cache/storybook/b124b7c47095b41d5ea618f285d096b0b3bcf3b8444e7fa72f6a80c348532f13/sb-vite/deps/chunk-HWACSCKG.js?v=2a05bdab:2985:16)
    at dispatchSetStateInternal (http://localhost:6007/node_modules/.cache/storybook/b124b7c47095b41d5ea618f285d096b0b3bcf3b8444e7fa72f6a80c348532f13/sb-vite/deps/chunk-HWACSCKG.js?v=2a05bdab:5350:20)
    at dispatchSetState (http://localhost:6007/node_modules/.cache/storybook/b124b7c47095b41d5ea618f285d096b0b3bcf3b8444e7fa72f6a80c348532f13/sb-vite/deps/chunk-HWACSCKG.js?v=2a05bdab:5321:9)
    at Object.setReference (http://localhost:6007/node_modules/.cache/storybook/b124b7c47095b41d5ea618f285d096b0b3bcf3b8444e7fa72f6a80c348532f13/sb-vite/deps/@floating-ui_react.js?v=88efab77:5570:7)
    at http://localhost:6007/src/Autocomplete/hooks/useAutocompleteListNav.ts:93:18
    at http://localhost:6007/src/Autocomplete/Autocomplete.rebuilt.tsx:104:7
    at http://localhost:6007/src/utils/mergeRefs.ts:5:9
    at Array.forEach (<anonymous>)
    at http://localhost:6007/src/utils/mergeRefs.ts:3:10

Changes

Fix for the crash

mergeRefs([...]) called inline creates a brand new callback function on every render of InputText. React tracks ref props by identity, if the ref prop is a different function than last render, React detaches the old one (calls it with null) then re-attaches the new one (calls it with the element). That detach chain ultimately calls refs.setReference(null) inside floating-ui, which calls setState. When this happened during floating-ui's flushSync call on window resize, it caused a nested synchronous React commit that exceeded the maximum update depth limit and crashed.

inputRef (our mergedInputRef from Autocomplete) and inputTextRef (an internal useRef, always stable) are both stable references. Memoizing with those as deps means mergedRef never changes identity, and React never schedules a detach/re-attach.

Upon fixing this though there were styling issues instead of the crash:

image

Fix for styling issues

Stable setReferenceElement

The refs object returned by useFloating can get a new object identity when floating-ui's internal state changes (e.g. after a position recalculation on resize). Since setReferenceElement listed refs as a dependency, it would get a new function identity whenever refs changed. That propagated up: referenceInputRef in Autocomplete.rebuilt.tsx depends on setReferenceElement, so it recreated too. Then mergedInputRef (which depends on referenceInputRef) recreated too. React then scheduled a detach/re-attach of the input ref, the same crash path described above.

The latestRefs pattern solves this by storing refs in a mutable useRef container that is updated synchronously every render. The setReferenceElement callback reads from the container at call time rather than capturing refs at creation time. Since a useRef container itself is always the same object identity, the dependency array can be empty, giving setReferenceElement a permanently stable identity.

size middleware sets width

Previously, the dropdown width was managed as React state (menuWidth), captured once when the input ref attached on mount via clientWidth. Because the above fixes made the ref stable, it no longer detaches and re-attaches on resize, which meant menuWidth was never refreshed after mount, the dropdown would show with a stale width after a screen resize.

The size middleware's apply callback runs on every autoUpdate trigger, so rects.reference.width is always the live, freshly-measured border-box width of the position reference element (the Form-Field-Wrapper). Moving width here eliminates the stale state entirely, using floating-ui's own recommended pattern for this purpose. It also removes the need for the menuWidth state variable and all associated code in Autocomplete.rebuilt.tsx.

Updating the visual regression snapshots

clientWidth is a DOM property that returns a rounded integer representing the element's content + padding width, explicitly excluding the border. Meanwhile, rects.reference.width comes from floating-ui's internal call to getBoundingClientRect().width. That returns a floating-point number representing the element's border-box width: content + padding + border.

The outcome of this is that the menu is 2px wider on both sides to include the border width. This is most obvious by using the onion view when inspecting the screenshots. As you slide from left to right you will see the menu increase in width slightly as it shifts from the old styles to the new styles. Otherwise, everything else should be functionally the same.

Testing

The component should look and behave the exact same as before except for no longer crashing on resize with the menu open.

Changes can be
tested via Pre-release


In Atlantis we use Github's built in pull request reviews.

@Aiden-Brine Aiden-Brine requested a review from a team as a code owner February 23, 2026 20:07
@Aiden-Brine Aiden-Brine marked this pull request as draft February 23, 2026 20:08
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Feb 23, 2026

Deploying atlantis with  Cloudflare Pages  Cloudflare Pages

Latest commit: abb0930
Status: ✅  Deploy successful!
Preview URL: https://e34c04dc.atlantis.pages.dev
Branch Preview URL: https://job-151844-max-depth-error.atlantis.pages.dev

View logs

@Aiden-Brine Aiden-Brine force-pushed the JOB-151844/max-depth-error branch from 0087dfe to 241f2e8 Compare February 26, 2026 00:22
@Aiden-Brine Aiden-Brine changed the title JOB_151844 Max depth error fix(components): Fix automcomplete crashing on resize larger [JOB-151844] Feb 27, 2026
@Aiden-Brine Aiden-Brine marked this pull request as ready for review February 27, 2026 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

1 participant