-
Notifications
You must be signed in to change notification settings - Fork 647
Optimize useAnchoredPosition hook for improved INP and rendering performance #7362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 699316e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Or, apply the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR optimizes the useAnchoredPosition hook to improve rendering performance and reduce layout thrashing for components using anchored positioning (ActionMenu, SelectPanel, Overlay, etc.). The optimization focuses on batching DOM reads/writes, using requestAnimationFrame for update coalescing, and minimizing unnecessary React re-renders through ref-based mutable state.
Key changes:
- Replaces state-based tracking with ref-based mutable state for values that don't need to trigger re-renders (previous position, height, pending status)
- Implements requestAnimationFrame batching to coalesce multiple update triggers into single calculations
- Replaces
useResizeObserverhook with direct ResizeObserver usage for more granular control over both anchor and floating elements - Deprecates the
dependenciesparameter (now ignored but kept for backwards compatibility)
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 11 comments.
| File | Description |
|---|---|
| packages/react/src/hooks/useAnchoredPosition.ts | Refactored hook implementation with RAF batching, ref-based state, direct ResizeObserver usage, and position equality checks to avoid unnecessary re-renders |
| packages/react/src/hooks/tests/useAnchoredPosition.test.tsx | Added comprehensive test suite with 18 tests covering basic functionality, provided refs, callbacks, settings, resize handling, cleanup, multiple instances, and edge cases |
packages/react/src/hooks/__tests__/useAnchoredPosition.test.tsx
Outdated
Show resolved
Hide resolved
- Add ResizeObserver environment check with fallback to window resize - Fix pin position logic to update prevHeight after pinning - Update dependencies test to reflect deprecated parameter behavior - Add comprehensive ResizeObserver tests - Add comments explaining state machine and design decisions - Only create ResizeObserver when both elements are present - Add changeset for patch release
| export function useAnchoredPosition( | ||
| settings?: AnchoredPositionHookSettings, | ||
| dependencies: React.DependencyList = [], | ||
| _dependencies?: React.DependencyList, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leaving this, but deprecated to avoid breaking consumers - we handle this internally, so we shouldn't need to also handle it externally
|
👋 Hi from github/github-ui! Your integration PR is ready: https://github.com/github/github-ui/pull/9372 |
Overview
This PR optimizes the
useAnchoredPositionhook to improve Interaction to Next Paint (INP) and overall rendering performance for components that use anchored positioning (ActionMenu, SelectPanel, Overlay, Autocomplete, etc.).Key Performance Improvements
1. Reduced Layout Thrashing
clientHeight,getBoundingClientRect) before any writesrequestAnimationFrameto coalesce multiple update triggers into a single calculation2. Optimized React Re-renders
3. Smarter Element Observation
useResizeObserverhook for more granular control4. Improved Late-Mounting Element Handling
useLayoutEffectExpected Web Vitals Improvements
INP (Interaction to Next Paint)
Opening/closing overlays with complex DOM
TBT (Total Blocking Time)
Rapid resize events or window resizing
CLS (Cumulative Layout Shift)
Position recalculations during page load
FID (First Input Delay)
Initial interaction with overlay triggers
How These Improvements Are Achieved
Impact by Usage Pattern
Key Optimizations
Why These Improvements?
INP (Interaction to Next Paint):
TBT (Total Blocking Time):
CLS (Cumulative Layout Shift):
API Changes
Changed
dependenciesparameter is now deprecated and ignored. Position updates are handled automatically via ResizeObserver and window resize events. The parameter is kept for backwards compatibility but has no effect.Changelog
New
useAnchoredPositionhook (18 tests covering basic functionality, provided refs, callbacks, settings, resize handling, cleanup, edge cases, and more)Changed
useAnchoredPositionnow automatically detects element size changes via ResizeObserverrequestAnimationFrameto prevent layout thrashingdependenciesparameter is deprecated (still accepted for backwards compatibility)Removed
useResizeObserverhook (now uses ResizeObserver directly for more control)Rollout strategy
This is a performance optimization with no breaking API changes. The
dependenciesparameter is deprecated but still accepted.Testing & Reviewing
npm test -- --run packages/react/src/hooks/__tests__/useAnchoredPosition.test.tsxMerge checklist