Skip to content

fix(react-components): support font icon styling - #36958

Open
Martin Hochel (Hotell) wants to merge 6 commits into
microsoft:masterfrom
Hotell:fix/react-components-font-icons
Open

Martin Hochel (Hotell) wants to merge 6 commits into
microsoft:masterfrom
Hotell:fix/react-components-font-icons

Conversation

@Hotell

@Hotell Martin Hochel (Hotell) commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Previous Behavior

Several v9 icon slots style only svg descendants. Fluent font icons render as i, so they miss icon sizing, block layout, and half-rating clipping rules.

PresenceBadge and the v0-to-v9 Attachment adapter also need glyph sizing, rather than only SVG width/height overrides. SVG stroke does not provide a visible font-glyph outline in forced colors.

The visual-test and migration Storybooks do not use the existing icon-variant webpack helper. Storybook's default asset filename can include workspace-relative path segments, resulting in font asset 404s in the migration Storybook.

New Behavior

Prerequisite status

The infrastructure prerequisite, #36971, has merged into master.

This fork-backed branch now includes upstream master, including the merged tooling refactor and the Nx 22.7.9 upgrade. The shared helper/CSS relocation, package exports, and existing docsite consumer changes are no longer part of this PR's diff.

The remaining changes are font-icon styling, additional Storybook enablement, and focused VRT coverage. The PR continues to originate from Hotell/fluentui and target upstream master; no force push was used.

Font-icon fixes and enablement

  • Extend icon-specific SVG selectors with equivalent i branches, preserving descendant/direct-child combinators and specificity.
  • Preserve existing fixed icon dimensions and custom-icon behavior. Input/SearchBox retain 16/20/24px sizing; font sizing reuses existing PresenceBadge and Attachment geometry rather than coupling it to overridable typography tokens.
  • Prevent half-filled rating glyphs from shrinking and provide a font-only forced-color outline.
  • Cover Input, SearchBox, Combobox/Dropdown/Option, Select, TagPicker, PresenceBadge, Rating, Attachment, and Storybook playground surfaces. Actual SVG geometry is unchanged.
  • Enable the shared atomic icon loader, font subsetting, and unsupported-icon SVG fallback in the VR and migration Storybooks. SVG remains the default; FLUENTUI_ICON_VARIANT=fonts selects font glyphs.
  • Emit font assets under static/media without workspace-relative filename segments, with a regression assertion in the shared helper test.
  • Retain nine patch change files, one per changed published package. No dependency changes.

Focused VRT regression coverage

  • Keep the full SVG Storybook and add a second, focused font build containing only the three icon-sizing stories.
  • Reuse the same component examples without overriding SearchBox, PresenceBadge, or RatingDisplay's default icons.
  • Run StoryWright sequentially against both build outputs through the existing test-vr target, forwarding caller options to both runs.
  • Combine screenshots in the existing output directory, with distinct SVG/font titles and a unique high-contrast story name.
  • Isolate webpack caches for SVG, full-font, and focused font-sizing builds and declare Nx inputs/outputs.
  • Collocate VRT configuration tests with the app's .storybook configuration.

Manual checks and limitations

The retained play checks remain manual aids, not a reliable CI assertion gate. They check icon boxes and font readiness; the font stories additionally reject SVG elements.

StoryWright does not explicitly await play completion or propagate its failures into its exit status. Screenshot success therefore does not prove those assertions passed. The existing VRT pipeline now captures focused font-sizing coverage alongside SVG coverage, but this is not a full-suite font-variant matrix or a new browser assertion runner.

Painted glyph size, half-value clipping, forced-color outlines, and Attachment coverage still require the visual/manual checks documented in docs/workflows/testing.md.

Validation

The following checks passed after merging current upstream master and restoring the locked Nx 22.7.9 dependencies:

  • yarn install --immutable — passed; the lockfile was not changed by installation.
  • NX_DAEMON=false yarn nx run-many -p scripts-storybook vr-tests-react-components -t test --skipNxCache -- --runInBand — passed: 5 suites, 21 tests, 2 snapshots; 1 existing todo.
  • NX_DAEMON=false yarn nx run-many -p scripts-storybook vr-tests-react-components -t type-check --excludeTaskDependencies — passed.
  • NX_DAEMON=false yarn nx run scripts-storybook:lint — passed.
  • NX_DAEMON=false yarn nx run-many -p vr-tests-react-components -t build-storybook build-storybook-fonts — passed: full SVG and focused font production builds.
  • NX_DAEMON=false yarn nx run vr-tests-react-components:test-vr --excludePatterns="'^(?!Icon.sizing)'" — passed: six sizing screenshots, three SVG and three font, through the combined target.
  • NX_DAEMON=false yarn nx format:check --base=upstream/master --head=HEAD and git diff --check — passed.

The shared webpack-test overlap was resolved by retaining this PR's font asset filename regression assertion. The merged infrastructure files are excluded from the PR diff.

Earlier browser checks on that same functional implementation confirmed 42 loaded font glyphs, zero SVG icons, and the expected icon dimensions in each of the three font stories.

The full unfiltered StoryWright suite and the broader component test matrix were not rerun for this upstream refresh.

Related Issue(s)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-avatar
Avatar
49.166 kB
15.658 kB
49.34 kB
15.717 kB
174 B
59 B
react-avatar
AvatarGroupItem
58.643 kB
18.172 kB
58.817 kB
18.231 kB
174 B
59 B
react-badge
PresenceBadge
25.012 kB
9.105 kB
25.186 kB
9.162 kB
174 B
57 B
react-combobox
Combobox (including child components)
137.042 kB
44.29 kB
137.068 kB
44.293 kB
26 B
3 B
react-combobox
Dropdown (including child components)
135.723 kB
43.711 kB
135.749 kB
43.715 kB
26 B
4 B
react-components
react-components: entire library
1.283 MB
322.134 kB
1.283 MB
322.29 kB
584 B
156 B
react-datepicker-compat
DatePicker Compat
216.641 kB
64.398 kB
216.678 kB
64.411 kB
37 B
13 B
react-input
Input
26.594 kB
8.782 kB
26.631 kB
8.793 kB
37 B
11 B
react-persona
Persona
56.119 kB
17.602 kB
56.293 kB
17.661 kB
174 B
59 B
react-select
Select
27.184 kB
9.835 kB
27.197 kB
9.838 kB
13 B
3 B
react-tag-picker
@fluentui/react-tag-picker - package
171.164 kB
53.355 kB
171.19 kB
53.36 kB
26 B
5 B
react-timepicker-compat
TimePicker
139.754 kB
45.561 kB
139.78 kB
45.57 kB
26 B
9 B
Unchanged fixtures
Package & Exports Size (minified/GZIP)
react-avatar
AvatarGroup
14.126 kB
5.692 kB
react-badge
Badge
24.49 kB
7.925 kB
react-badge
CounterBadge
25.212 kB
8.184 kB
react-components
react-components: all base hooks
219.615 kB
68.539 kB
react-components
react-components: Button, FluentProvider & webLightTheme
68.214 kB
19.863 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
223.278 kB
67.379 kB
react-components
react-components: FluentProvider & webLightTheme
41.444 kB
13.893 kB
react-headless-components-preview
react-headless-components-preview: entire library
228.365 kB
67.574 kB
react-headless-components-preview
@fluentui/react-headless-components-preview/tag-picker
50.254 kB
16.375 kB
react-headless-components-preview
@fluentui/react-headless-components-preview/teaching-popover
33.739 kB
11.083 kB
react-portal-compat
PortalCompatProvider
5.198 kB
2.104 kB
react-table
DataGrid
143.634 kB
42.543 kB
react-table
Table (Primitives only)
38.903 kB
13.017 kB
react-table
Table as DataGrid
119.146 kB
33.785 kB
react-table
Table (Selection only)
67.409 kB
19.301 kB
react-table
Table (Sort only)
66.072 kB
18.926 kB
react-tags
InteractionTag
13.986 kB
5.531 kB
react-tags
Tag
30.614 kB
9.763 kB
react-tags
TagGroup
69.63 kB
21.545 kB
react-tree
FlatTree
132.701 kB
39.468 kB
react-tree
PersonaFlatTree
134.558 kB
39.973 kB
react-tree
PersonaTree
130.645 kB
38.769 kB
react-tree
Tree
128.788 kB
38.287 kB
🤖 This report was generated against 335c5de3c19538262feb63dbb9c0e2b7d3ff1b57

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

Final-commit glyph sizing, half-rating clipping, and forced-color outlines still need human browser validation.

No open issues 🎉

What changed in this PR

Extends Fluent UI v9 icon styling to support font glyphs alongside SVG icons, with supporting Storybook configuration and validation fixtures.

Changes:

  • Adds font-icon sizing, layout, half-rating clipping, and forced-color outline styles.
  • Enables icon variants in visual-test and migration Storybooks, with cache inputs and corrected font asset filenames.
  • Adds configuration tests, manual validation stories, documentation, and nine patch change files.
File Description
scripts/​storybook/​src/​react-icons-webpack.spec.js Tests default SVG and font configuration.
packages/​react-components/​react-tag-picker/​library/​src/​components/​TagPickerControl/​useTagPickerControlStyles.styles.ts Extends block layout to font icons.
packages/​react-components/​react-storybook-addon-playground/​src/​playground/​Playground.styles.ts Applies playground icon styles to glyphs.
packages/​react-components/​react-select/​library/​src/​components/​Select/​useSelectStyles.styles.ts Extends block layout to font icons.
packages/​react-components/​react-search/​library/​src/​components/​SearchBox/​useSearchBoxStyles.styles.ts Sizes font dismiss icons.
packages/​react-components/​react-rating/​library/​src/​components/​RatingItem/​useRatingItemStyles.styles.ts Adds glyph clipping support and forced-color outlines.
packages/​react-components/​react-migration-v0-v9/​stories/​src/​Attachment/​index.stories.tsx Exports new Attachment fixtures.
packages/​react-components/​react-migration-v0-v9/​stories/​src/​Attachment/​Icon.stories.tsx Adds fixed-size and typography-override checks.
packages/​react-components/​react-migration-v0-v9/​stories/​project.json Adds icon-variant cache input.
packages/​react-components/​react-migration-v0-v9/​stories/​.storybook/​main.js Enables shared icon configuration.
packages/​react-components/​react-migration-v0-v9/​library/​src/​components/​Attachment/​AttachmentIcon.styles.ts Preserves fixed Attachment glyph sizing.
packages/​react-components/​react-input/​library/​src/​components/​Input/​useInputStyles.styles.ts Applies existing icon sizes to glyphs.
packages/​react-components/​react-combobox/​library/​src/​components/​Option/​useOptionStyles.styles.ts Extends block layout to font icons.
packages/​react-components/​react-combobox/​library/​src/​components/​Dropdown/​useDropdownStyles.styles.ts Extends block layout to font icons.
packages/​react-components/​react-combobox/​library/​src/​components/​Combobox/​useComboboxStyles.styles.ts Extends block layout to font icons.
packages/​react-components/​react-badge/​library/​src/​components/​PresenceBadge/​usePresenceBadgeStyles.styles.ts Adds fixed PresenceBadge glyph sizes.
docs/​workflows/​testing.md Documents renderer checks and automation limitations.
change/​@fluentui-react-tag-picker-14119948-e200-49f9-b82a-e7fca44f34a2.json Records TagPicker patch release.
change/​@fluentui-react-storybook-addon-playground-4df3df71-efe4-45bc-82d9-74e37bd5ef0d.json Records playground patch release.
change/​@fluentui-react-select-42847cbe-c70a-4ede-bbf6-badf76db0931.json Records Select patch release.
change/​@fluentui-react-search-4938f326-9f13-432e-9e7b-79ba55f71f7d.json Records SearchBox patch release.
change/​@fluentui-react-rating-e34d747d-5398-48ce-9026-35e7e43963fe.json Records Rating patch release.
change/​@fluentui-react-migration-v0-v9-e3fbb1ca-5d2e-4bb8-9af5-41f264331e98.json Records migration adapter patch release.
change/​@fluentui-react-input-1239ce15-9c71-4aca-b011-e53de36cf38c.json Records Input patch release.
change/​@fluentui-react-combobox-1059704a-69e2-4393-941a-18dc64ce4899.json Records Combobox patch release.
change/​@fluentui-react-badge-e5066033-ba54-4617-9bb9-6a54247ac43c.json Records Badge patch release.
apps/​vr-tests-react-components/​src/​stories/​PresenseBadge/​PresenceBadgeSizes.stories.tsx Adds theme variants and custom icons.
apps/​vr-tests-react-components/​src/​stories/​Input/​Input.stories.tsx Adds size variants and mixed-renderer fixtures.
apps/​vr-tests-react-components/​src/​stories/​IconSizing.stories.tsx Adds manual sizing and font-readiness checks.
apps/​vr-tests-react-components/​project.json Adds icon-variant build cache input.
apps/​vr-tests-react-components/​.storybook/​main.js Enables shared icon configuration.
.storybook/​react-icons-webpack.js Removes workspace-relative segments from font asset names.

Review effort: Balanced

@github-actions

Copy link
Copy Markdown

Pull request demo site: URL

@@ -77,6 +77,10 @@ function configureReactIcons(options) {
config.module.rules.push({

@github-actions github-actions Bot Oct 20, 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/Avatar Converged 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Avatar Converged.badgeMask.normal.chromium.png 4 Changed
vr-tests-react-components/Icon sizing 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Icon sizing.Default Theme.fixed icon sizes.chromium.png 0 Added
vr-tests-react-components/Icon sizing.Overridden tokens high contrast.fixed icon sizes.chromium.png 0 Added
vr-tests-react-components/Icon sizing.Overridden tokens.fixed icon sizes.chromium.png 0 Added
vr-tests-react-components/Icon sizing fonts 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Icon sizing fonts.Default Theme.fixed icon sizes.chromium.png 0 Added
vr-tests-react-components/Icon sizing fonts.Overridden tokens high contrast.fixed icon sizes.chromium.png 0 Added
vr-tests-react-components/Icon sizing fonts.Overridden tokens.fixed icon sizes.chromium.png 0 Added
vr-tests-react-components/Input Converged 5 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Input Converged.Icon Sizes - Dark Mode.default.chromium.png 0 Added
vr-tests-react-components/Input Converged.Icon Sizes - High Contrast.default.chromium.png 0 Added
vr-tests-react-components/Input Converged.Icon Sizes - RTL.default.chromium.png 0 Added
vr-tests-react-components/Input Converged.Icon Sizes.default.chromium.png 0 Added
vr-tests-react-components/Input Converged.Mixed Icon Renderers.default.chromium.png 0 Added
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default.submenus open.chromium.png 413 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 615 Changed
vr-tests-react-components/Positioning.Positioning end.chromium.png 880 Changed
vr-tests-react-components/PresenceBadge Converged - sizes 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/PresenceBadge Converged - sizes.Custom Icons.chromium.png 0 Added
vr-tests-react-components/PresenceBadge Converged - sizes.default - Dark Mode.chromium.png 0 Added
vr-tests-react-components/PresenceBadge Converged - sizes.default - High Contrast.chromium.png 0 Added
vr-tests-react-components/ProgressBar converged 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 77 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 2 Changed
vr-tests-react-components/TagPicker 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/TagPicker.disabled.disabled input hover.chromium.png 677 Changed
vr-tests/Callout 8 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/Callout.Bottom left edge.default.chromium.png 2195 Changed
vr-tests/Callout.Bottom right edge.default.chromium.png 1130 Changed
vr-tests/Callout.Bottom right edge - RTL.default.chromium.png 1124 Changed
vr-tests/Callout.Right center.default.chromium.png 2117 Changed
vr-tests/Callout.Right bottom edge.default.chromium.png 3095 Changed
vr-tests/Callout.No callout width specified.default.chromium.png 2143 Changed
vr-tests/Callout.Left bottom edge.default.chromium.png 3182 Changed
vr-tests/Callout.Top left edge.default.chromium.png 2212 Changed
vr-tests/react-charting-LineChart 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/react-charting-LineChart.Multiple - RTL.default.chromium.png 200 Changed
vr-tests/react-charting-LineChart.Multiple.default.chromium.png 192 Changed

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

Build the font sizing stories separately and capture both SVG and font defaults through the existing VRT target. Isolate webpack caches and collocate configuration tests with the VRT Storybook config.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Collocate the icon webpack helper, CSS and tests in scripts-storybook. Export the helper through the package API, update consumers and track the tooling in Storybook cache inputs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the existing icon helper and CSS into scripts-storybook without changing their implementation. Export the shared API, update existing docsites and cache inputs, and cover current SVG/font configuration behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Stack font icon support and focused VRT coverage on the independent infrastructure refactor in microsoft#36970, preserving the existing functional changes and branch history.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Hotell
Martin Hochel (Hotell) changed the base branch from master to refactor/storybook-icon-tooling October 21, 2026 11:20
@Hotell
Martin Hochel (Hotell) changed the base branch from refactor/storybook-icon-tooling to master October 21, 2026 12:26
Bring the font icon support PR up to date after microsoft#36971 merged, including upstream's Nx 22.7.9 upgrade. Preserve the font asset filename regression assertion while resolving the shared test overlap.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@Hotell
Martin Hochel (Hotell) marked this pull request as ready for review October 21, 2026 17:23
@Hotell

Copy link
Copy Markdown
Contributor Author

both font/svg icon + sizes are now part of VRT
image

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants