Skip to content

Fix and refactor UnderlineNav to resolve CLS issues and improve performance/code quality#7622

Merged
iansan5653 merged 2 commits intounderline-nav-full-css-spikefrom
copilot/sub-pr-7506-again
Mar 4, 2026
Merged

Fix and refactor UnderlineNav to resolve CLS issues and improve performance/code quality#7622
iansan5653 merged 2 commits intounderline-nav-full-css-spikefrom
copilot/sub-pr-7506-again

Conversation

Copy link
Contributor

Copilot AI commented Mar 4, 2026

UnderlineNav caused CLS by measuring item widths in JS after hydration to determine overflow. This replaces that approach with CSS-based overflow detection, eliminating layout shift and removing substantial complexity.

How overflow works now:

  • Items wrap onto subsequent lines clipped by overflow: hidden — visually disappear without JS
  • Overflow menu button visibility controlled by scroll-state container queries (pure CSS)
  • Each item registers an IntersectionObserver via context to self-report when overflowed; parent renders those items in the overflow menu
  • If any item ever overflowed, all tab icons are suppressed for the component lifetime (prevents icon-size-induced flickering)

What changed:

  • Overflow detection: JS width measurement → CSS wrapping + scroll-state container queries
  • Overflow menu: custom implementation → ActionMenu (fixes positioning, removes ~100 LOC)
  • Item tracking: React.Children API → descendant registry via context
  • Icon visibility: JS-controlled props → pure CSS
  • Overflow button is now right-aligned (always at the trailing edge, not next to the last visible item)
  • Current item styled distinctively when it appears in the overflow menu: current item in overflow menu
  • If the first item has an extremely long label and cannot fit at all, it truncates with ellipsis rather than being moved to the menu: truncated first item

Breaking behavioral changes:

  • The current item is no longer guaranteed to remain visible outside the overflow menu — impossible to guarantee with the CSS wrapping approach
  • Items no longer need to be direct children; fragments and wrapper components are now supported

Changelog

New

  • UnderlineNav items can now be wrapped in fragments or intermediate components (no longer requires direct children)

Changed

  • UnderlineNav overflow detection is now CSS-based, eliminating CLS
  • Overflow menu uses ActionMenu; button is right-aligned
  • Current item may appear in the overflow menu when space is constrained (styled with a leading indicator)
  • Tab icons are suppressed for the component lifetime once any overflow has occurred

Removed

  • JS width-measurement logic for overflow calculation
  • Custom overflow menu implementation

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

Overflow behavior is best verified by resizing the browser window. The flex layout is easiest to inspect using Chrome DevTools' flex inspector — it clearly shows where wrapped items are hiding.

Merge checklist


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

@changeset-bot
Copy link

changeset-bot bot commented Mar 4, 2026

🦋 Changeset detected

Latest commit: 984b15d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@primer/react Minor

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

Co-authored-by: iansan5653 <2294248+iansan5653@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix and refactor UnderlineNav for performance and CLS issues Fix and refactor UnderlineNav to resolve CLS issues and improve performance/code quality Mar 4, 2026
@iansan5653 iansan5653 marked this pull request as ready for review March 4, 2026 19:58
@iansan5653 iansan5653 requested a review from a team as a code owner March 4, 2026 19:58
@iansan5653 iansan5653 requested a review from llastflowers March 4, 2026 19:58
@iansan5653 iansan5653 merged commit 4d8d5e6 into underline-nav-full-css-spike Mar 4, 2026
@iansan5653 iansan5653 deleted the copilot/sub-pr-7506-again branch March 4, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants