Skip to content

fix(react-nav): show selection indicator on selected NavSubItem - #36778

Open
Geervan (Geervan) wants to merge 3 commits into
microsoft:masterfrom
Geervan:fix/nav-sub-item-indicator
Open

Geervan (Geervan) wants to merge 3 commits into
microsoft:masterfrom
Geervan:fix/nav-sub-item-indicator

Conversation

@Geervan

@Geervan Geervan (Geervan) commented Sep 22, 2026 •

Copy link
Copy Markdown

Fixes #36754

Description

Fixes an issue where the selection indicator on a NavSubItem inside an expanded NavCategory was invisible or misaligned when selected.

Changes

  1. Reordered class merging: Swapped base and smallBase in mergeClasses so smallBase (paddingInlineStart: 40px) correctly overrides base (paddingInlineStart: 46px) when density === 'small'.
  2. Density-specific indicator offsets:
    • Medium density (46px padding): Set indicator margin to -(indicatorOffset + 36)px (-52px), netting to -6px ($46\text{px} - 52\text{px}$).
    • Small density (40px padding): Added smallSelectedIndicator with margin -(indicatorOffset + 30)px (-46px), netting to -6px ($40\text{px} - 46\text{px}$).
    • Both densities now align with the top-level NavItem selection indicator line at -6px.
  3. Removed clipping styles: Removed overflow: hidden and transform: translateZ(0) from NavSubItemGroup root styles so child selection indicators are not clipped.
  4. Added regression tests: Added unit tests in NavSubItem.test.tsx verifying density classes and selection indicator behavior.

Validation

  • Verified in Storybook across Nav stories (Basic, Controlled, Variable Density Items).
  • Unit tests (yarn nx run react-nav:test), lint (yarn nx run react-nav:lint), and type-checking (yarn nx run react-nav:type-check) all pass.

@Geervan

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@Geervan
Geervan (Geervan) force-pushed the fix/nav-sub-item-indicator branch from 006f38b to 3ea8491 Compare October 9, 2026 15:08
@Geervan

Copy link
Copy Markdown
Author

Paul Mardling (@PaulGMardling) Thanks for catching that! Updated both the class merge order and the indicator offsets as suggested:

  1. Padding override order: Reordered mergeClasses so smallBase (40px) now correctly overrides base (46px) when density === 'small'.
  2. Indicator offsets:
    • Medium density: Margin set to -(indicatorOffset + 36)px (-52px), netting to -6px ($46\text{px} - 52\text{px}$).
    • Small density: Margin set to -(indicatorOffset + 30)px (-46px), netting to -6px ($40\text{px} - 46\text{px}$).
      Both densities now align with top-level NavItem indicators (-6px).
  3. Regression tests: Added unit tests in NavSubItem.test.tsx verifying density classes and selection indicator behavior.
    let me know if anything else feels off

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The tests do not cover the visual regression, and the implemented offsets conflict with the PR description.

2 open findings
What changed in this PR

Fixes selected NavSubItem indicators being clipped inside expanded categories.

Changes:

  • Adjusts density-specific indicator positioning.
  • Removes clipping styles from subitem groups.
  • Adds style-hook tests and a patch change file.
File Description
useNavSubItemGroupStyles.styles.ts Removes indicator-clipping styles.
useNavSubItemStyles.styles.ts Adds small-density indicator positioning.
NavSubItem.test.tsx Adds density and selection style tests.
@fluentui-react-nav-indicator-fix.json Records the patch release.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-components
react-components: entire library
1.286 MB
323.627 kB
1.287 MB
323.729 kB
1.062 kB
102 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-components
react-components: all base hooks
222.873 kB
69.876 kB
react-components
react-components: Button, FluentProvider & webLightTheme
68.229 kB
19.872 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.864 kB
68.687 kB
react-components
react-components: FluentProvider & webLightTheme
41.459 kB
13.908 kB
react-headless-components-preview
react-headless-components-preview: entire library
244.837 kB
69.109 kB
react-headless-components-preview
@fluentui/react-headless-components-preview/tag-picker
54.101 kB
17.741 kB
react-headless-components-preview
@fluentui/react-headless-components-preview/teaching-popover
36.155 kB
12.018 kB
react-portal-compat
PortalCompatProvider
5.202 kB
2.106 kB
react-timepicker-compat
TimePicker
143.301 kB
46.941 kB
🤖 This report was generated against cffaa5b19a74550e5f553ebe755ca9dc9dc0bb4d

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

Pull request demo site: URL

@@ -0,0 +1,7 @@
{

@github-actions github-actions Bot Oct 9, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Nav Converged 4 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Nav Converged.selected item and sub item - Dark Mode.normal.chromium.png 0 Added
vr-tests-react-components/Nav Converged.selected item and sub item - High Contrast.normal.chromium.png 0 Added
vr-tests-react-components/Nav Converged.selected item and sub item - RTL.normal.chromium.png 0 Added
vr-tests-react-components/Nav Converged.selected item and sub item.normal.chromium.png 0 Added
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 163 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 499 Changed
vr-tests-react-components/ProgressBar converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 92 Changed

@Geervan
Geervan (Geervan) force-pushed the fix/nav-sub-item-indicator branch from 3ea8491 to 05c8e2d Compare October 9, 2026 18:45
@Geervan

Copy link
Copy Markdown
Author

Updated the PR with the following:

  1. Indicator Alignment & Density Fix: Corrected the medium density offset to -52px (46px padding - 52px = -6px) and small density to -46px (40px padding - 46px = -6px), ensuring perfect vertical alignment with top-level NavItem indicators across both densities.
  2. Clipping Fix: Removed overflow: hidden and transform: translateZ(0) from NavSubItemGroup so child selection indicators render unclipped.
  3. Tests & Validation: Added unit tests in NavSubItem.test.tsx and NavSubItemGroup.test.tsx for density styling hooks and unclipped root classes. Visual rendering was verified in Storybook across default, small-density, dark mode, high contrast, and RTL.
  4. Description: Updated the PR description with the exact offset values and calculations.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The tests do not verify the regression behavior, and the new layout calculation violates the design-token convention.

4 open findings

🧠 Review effort: Balanced

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The added tests do not actually verify the corrected indicator offsets or clipping behavior.

2 open findings
2 resolved since last review

🧠 Review effort: Balanced

@Geervan
Geervan (Geervan) requested a review from a team as a code owner October 10, 2026 06:44
},
smallSelectedIndicator: {
'::after': {
marginInlineStart: `calc(-1 * (${tokens.spacingHorizontalMNudge} + ${subItemSmallIndent} + ${tokens.spacingHorizontalSNudge}))`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we keep both margins tied to the shared navItemTokens.indicatorOffset? For example:

<FluentProvider
  theme={{ ...webLightTheme, spacingHorizontalSNudge: '8px' }}
>
  {/* Nav containing top-level items and an expanded sub-item group */}
</FluentProvider>

Top-level indicators remain at 10px - 16px = -6px, but these expressions cancel the sub-item padding and leave -spacingHorizontalSNudge = -8px in both densities. That moves the selection rail 2px outward when selecting a sub-item.

An illustrative adjustment for the two values is:

// Medium
marginInlineStart: `calc(-1 * (${subItemMediumIndent} + ${navItemTokens.indicatorOffset}px))`,

// Small
marginInlineStart: `calc(-1 * (${subItemSmallIndent} + ${navItemTokens.indicatorOffset}px))`,

This preserves the same spacingHorizontalMNudge - indicatorOffset position as top-level items. Could we also cover the override above in a regression test for both densities?

This branch has not been deployed

No deployments
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.

[Bug]: Selected NavSubItem shows no indicator inside expanded NavCategory

4 participants