Skip to content

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

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

Geervan (Geervan) wants to merge 1 commit 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

Comment on lines +33 to +35
smallSelectedIndicator: {
'::after': {
marginInlineStart: `-${navItemTokens.indicatorOffset + 32}px`,

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 update both the padding class order in mergeClasses and the indicator offsets for the two densities together? smallBase currently comes before base, so both densities retain 46px start padding. The new −48px small-density margin therefore positions the indicator at −2px, while the −54px medium-density margin positions it at −8px. Top-level indicators sit at −6px, so neither density aligns with them.

Making smallBase override base would give small-density items the intended 40px padding. With that corrected, margins of −46px for small and −52px for medium would align both indicators at −6px. Could we also add a regression check for alignment with top-level items in both densities?

@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.

Comment on lines +38 to +40
it('applies medium density and indicator styles when selected in medium density', () => {
const state = createBaseState({ selected: true, density: 'medium' });
const { result } = renderHook(() => useNavSubItemStyles_unstable(state));
Comment on lines +33 to +35
smallSelectedIndicator: {
'::after': {
marginInlineStart: `-${navItemTokens.indicatorOffset + 30}px`,
@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.285 MB
323.183 kB
1.285 MB
323.188 kB
11 B
5 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-components
react-components: all base hooks
218.419 kB
68.524 kB
react-components
react-components: Button, FluentProvider & webLightTheme
67.693 kB
19.589 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.328 kB
68.391 kB
react-components
react-components: FluentProvider & webLightTheme
40.923 kB
13.66 kB
react-headless-components-preview
react-headless-components-preview: entire library
244.37 kB
68.942 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 6e52576d457f0ca13225ea2712e0db7bd1c27e28

@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

Pull request demo site: URL

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

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/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 620 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 17 Changed
vr-tests-react-components/ProgressBar converged 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 1 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 69 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 78 Changed
vr-tests-react-components/TagPicker 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled - RTL.disabled input hover.chromium.png 635 Changed
vr-tests-react-components/TagPicker.disabled.disabled input hover.chromium.png 677 Changed

There were 2 duplicate changes discarded. Check the build logs for more information.

@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

Comment on lines +43 to +44
const { result } = renderHook(() => useNavSubItemGroupStyles_unstable(state));
expect(result.current.root.className).toContain(navSubItemGroupClassNames.root);
Comment on lines +33 to +36
smallSelectedIndicator: {
'::after': {
marginInlineStart: `-${navItemTokens.indicatorOffset + 30}px`,
},
@Geervan
Geervan (Geervan) force-pushed the fix/nav-sub-item-indicator branch from 05c8e2d to b452348 Compare October 9, 2026 18:57

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