Skip to content

refactor: migrate from Material Icons to Material Symbols Outlined#35449

Merged
rjvelazco merged 8 commits intomainfrom
issue-35447-replace-material-icons-with-material-symbols-in-core-web
Apr 24, 2026
Merged

refactor: migrate from Material Icons to Material Symbols Outlined#35449
rjvelazco merged 8 commits intomainfrom
issue-35447-replace-material-icons-with-material-symbols-in-core-web

Conversation

@rjvelazco
Copy link
Copy Markdown
Member

@rjvelazco rjvelazco commented Apr 24, 2026

Summary

Migrates core-web from the deprecated Material Icons font to Material Symbols Outlined (variable font). Closes #35447.

The old Material Icons library is in maintenance mode; Material Symbols is the actively-maintained successor, ships the full icon set, and exposes variable-font axes (FILL, wght, GRAD, opsz) so future UI states can morph icons without shipping extra font files.

Video

video.mov

What changed

Font + CSS

  • Added MaterialSymbolsOutlined-Regular.woff2 (variable font, weights 100–700) in apps/dotcms-ui/src/assets/.
  • Removed legacy fonts: MaterialIcons-Regular.ttf, MaterialIconsOutlined-Regular.otf.
  • New shared partial libs/dotcms-scss/shared/_material-symbols-outlined.scss defines the @font-face, the .material-symbols-outlined class (with sensible variable-axis defaults), and a :root { --mdc-icon-font: "Material Symbols Outlined" } override. Imported by the main Angular stylesheet and the JSP stylesheet — one source of truth for both the admin SPA and the legacy JSPs.
  • Old _material-icons.scss, material-icons.css, and the dev-only material-symbols-outlined.css for the template-builder Storybook updated to match.
  • Compiled JSP output regenerated: libs/dotcms-scss/jsp/css/dotcms.css and dotCMS/src/main/webapp/html/css/dijit-dotcms/dotcms.css.

Class migration

  • Every class="material-icons" replaced with class="material-symbols-outlined" across Angular templates, SCSS (including ::ng-deep rules), dotCMS JSPs, VTL default container, and legacy dojo JS.

Webcomponents (libs/dotcms-webcomponents)

  • Stencil globalStyle: 'src/global/global.scss' registered so standalone builds / Storybook get the --mdc-icon-font override too.
  • @material/mwc-icon reads font-family: var(--mdc-icon-font, 'Material Icons') from its shadow DOM. By setting the variable at :root in the consumer app, every mwc-icon inherits the new font across the shadow boundary — no component markup change needed.
  • dot-contentlet-lock-icon: fixed latent bug — was rendering 'locked', which is not a valid ligature in either Material Icons or Material Symbols. Now uses 'lock'.
  • dot-material-icon-picker:
    • Swept material-icon-classes.tsx against Google's Material Symbols Outlined codepoints file. 1778 → 1763 entries. 15 stale duplicates removed (e.g. play_circle_filled/play_circle_outline → the FILL axis of play_circle handles it now; panorama_*_select suffix dropped; person_add_alt_1person_add). 1 true rename: wifi_tethering_error_roundedwifi_tethering_error. 2 dropped with no equivalent: catching_pokemon, facebook.
    • Preview icon no longer renders letter-by-letter while typing — only renders when the input value is an exact match in the suggestion list.

Acceptance criteria (from #35447)

  • Audit core-web for every Material Icons usage.
  • Swap @font-face to Material Symbols Outlined.
  • Replace .material-icons class usages with .material-symbols-outlined.
  • Verify icon name parity; document renames/removals (icon-picker list audit).
  • Remove the old Material Icons font import and dead CSS.
  • Preserve visual parity (size, color, alignment, spacing unchanged — axis defaults pinned at FILL 0, wght 400, GRAD 0, opsz 24).
  • Smoke-test across Chrome and Firefox — please verify during review.

Bundle impact

  • Added: MaterialSymbolsOutlined-Regular.woff23.7 MB (full variable font, all ~4,200 glyphs, 5 weight range, all axes).
  • Removed: MaterialIconsOutlined-Regular.otf (~331 KB) + MaterialIcons-Regular.ttf (~347 KB) ≈ 678 KB.
  • Net increase: ~3 MB on the assets layer, loaded lazily via font-display: swap.
  • The woff2 is served from /dotAdmin/assets/, so browser cache amortizes the cost across sessions. If this is a concern I can follow up with a subsetted variant (only the icons actually referenced in the repo — ~200 unique names — which would bring it back under 500 KB).

Out of scope

  • PrimeNG icons (pi pi-…) and SVG-based icons — unchanged, as per the issue.
  • Introducing a dot-icon wrapper — deferred; this PR keeps the migration strictly to a font/class swap so it stays reviewable.

Risk / things to watch during review

  • Caller-side dot-select-button icon="…": This webcomponent takes the icon name as a prop. I audited dot-select-button's own code and its e2e tests (code, backup, help — all valid), but consumer apps could still pass a stale Material Icons name. Worth a quick grep of the admin UI's <dot-select-button usages.
  • JSP / legacy dojo code: The .material-icons class was swapped in JSPs and dotcms-block-editor.js, but those views are harder to exercise automatically — please sanity-check once in the running app.
  • Shadow DOM inheritance: Relies on --mdc-icon-font crossing the shadow boundary. Verified locally that the override reaches mwc-icon's shadow root; if any report comes in of icons showing as literal text, that's the first thing to check in DevTools → Computed font-family.

This PR fixes: #35447

This commit updates the icon usage across various components in the application, replacing instances of  with . The changes include updates to HTML templates, stylesheets, and tests to ensure consistency with the new icon set. Additionally, the old Material Icons assets have been removed, and the new Material Symbols Outlined font has been added to the project.

- Updated icon classes in component templates and styles.
- Removed deprecated Material Icons assets.
- Added new Material Symbols Outlined font files and styles.

This transition aims to enhance the visual consistency and maintainability of the iconography used throughout the application.
@github-actions github-actions Bot added Area : Backend PR changes Java/Maven backend code Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries labels Apr 24, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 24, 2026

Claude finished @rjvelazco's task in 1m 15s —— View job


PR Final Review (Pass 3)

  • Check current state of previously-flagged files
  • Review new commits since last review
  • Compile final findings

All three blocking items from prior reviews are resolved. The codebase is clean.

dotcms-block-editor.js scoped CSS bug — Fixed in c56a7ed0. The .material-symbols-outlined[_ngcontent-%COMP%] rule now reads font-family:'Material Symbols Outlined'. Zero remaining Material Icons references in the file. ✅

documentation.json stale entries — Fixed in c56a7ed0. The font-family: 'Material Icons' and MaterialIcons-Regular.ttf references in the suggestions.component snapshot are patched. ✅

legacy-custom-field.jsp broken @font-face — Fixed in 31935a93. Now correctly points to MaterialSymbolsOutlined-Regular.woff2. ✅

suggestions.component.css duplicate block — Removed in 31935a93. The local .material-symbols-outlined rule that duplicated the global stylesheet is gone; the global rule via Angular Emulated encapsulation handles it correctly. ✅

font-feature-settings cross-browser31935a93 added the unprefixed "liga" rule alongside -webkit-font-feature-settings in _material-symbols-outlined.scss, dotcms.css, and material-symbols-outlined.css. Ligatures now render on non-WebKit browsers. ✅

dot-empty-state spec26073a72 trims textContent before asserting, which is the right fix when Prettier splits <span>{{ icon }}</span> to multiple lines and introduces whitespace. ✅

Full sweep — No material-icons class, Material Icons font-family, MaterialIcons-Regular.{ttf,otf} references remain in any .ts, .html, .scss, .css, .js, .jsp, or .vtl file.

Ready to merge.

…ols Outlined

This commit enhances the HTML structure of various components by ensuring consistent formatting for icon elements. Additionally, it refines the CSS for Material Symbols Outlined, improving readability and maintainability by aligning font-variation-settings across multiple stylesheets.

- Updated HTML templates to format icon elements with proper indentation.
- Refactored CSS to improve readability by breaking down font-variation-settings into multiple lines.
- Ensured consistent usage of single quotes for font-family and other properties.

These changes aim to enhance code clarity and maintainability across the application.
@rjvelazco rjvelazco moved this to In Progress in dotCMS - Product Planning Apr 24, 2026
@rjvelazco rjvelazco moved this from In Progress to New in dotCMS - Product Planning Apr 24, 2026
@rjvelazco rjvelazco moved this from New to In Progress in dotCMS - Product Planning Apr 24, 2026
- Fix broken @font-face in legacy-custom-field.jsp that still referenced
  the deleted MaterialIcons-Regular.ttf (icons would 404 and render as
  literal ligature names)
- Add unprefixed `font-feature-settings: 'liga'` alongside the webkit
  prefix so ligatures render on non-webkit browsers
- Drop duplicate .material-symbols-outlined block from the block-editor
  suggestions component CSS; Angular Emulated encapsulation lets the
  global rule apply, so the local copy was just a maintenance hazard

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rjvelazco
Copy link
Copy Markdown
Member Author

@claude review again

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 24, 2026

Claude finished @rjvelazco's task in 4m 37s —— View job


PR Review: Material Icons → Material Symbols Outlined Migration

  • Gather context and read changed files
  • Review font/CSS changes
  • Review class migration across templates
  • Review webcomponents changes
  • Review JSP/legacy code changes
  • Review test changes
  • Compile findings and post review

Overall Assessment

This is a well-executed font migration. The approach is architecturally sound, the sweep is thorough, and the code is clean. A few items worth calling out below.


What's Done Well

Clean shadow DOM strategy — Using --mdc-icon-font at :root to cross the shadow boundary is the correct pattern for @material/mwc-icon. The variable propagates through shadow roots correctly and avoids markup changes in every consumer.

Variable font axis defaultsFILL 0, wght 400, GRAD 0, opsz 24 are sensible defaults that maintain visual parity with the old Material Icons Outlined appearance.

Complete sweep — Grepping the whole codebase for leftover material-icons class usages, MaterialIcons font references, and old font file imports turns up nothing. The migration is exhaustively applied.

dot-contentlet-lock-icon fix (lockedlock) — locked was never a valid ligature in either icon font. Good catch.

isValidIcon preview fix — The new check (this.value !== LABEL_IMPORTANT_ICON && this.suggestionlist.includes(this.value)) correctly prevents letter-by-letter rendering while the user is mid-type. Clean improvement.

Icon list audit — Sweeping 1778 → 1763 entries against the real codepoints file and documenting every removal/rename is excellent attention to detail.


Issues & Concerns

1. documentation.json — stale CSS snapshot (minor)

At line 161886 in documentation.json, the styleUrlsData for suggestions.component contains a stale snapshot:

.material-symbols-outlined {
    font-family: 'Material Icons';   /* ← wrong font-family! */
    ...
}

The class name was updated from material-icons to material-symbols-outlined, but the font-family value still points to 'Material Icons'. The actual source file (suggestions.component.css) correctly removes the entire block — so this only affects generated docs, not runtime. Since documentation.json is compodoc-generated, re-running compodoc would regenerate it cleanly.

Similarly, line 174526 has a defaultValue that embeds old MaterialIcons-Regular.ttf font references. Same cause — stale snapshot from before the source file was updated.

Fix this →

2. Bundle size: +3 MB net (informational)

The PR description accurately documents this: the full variable woff2 is 3.7 MB (all ~4200 glyphs, 5 weight range), minus the ~678 KB removed. The PR notes a possible follow-up with a subsetted variant (~200 unique names → under 500 KB). Worth tracking as a follow-up issue if admin load time is a concern.

3. webcomponents/global.scss doesn't register the @font-face (low risk)

libs/dotcms-webcomponents/src/global/global.scss only sets --mdc-icon-font — it relies on the consuming app to have registered the @font-face:

// global.scss
:root {
    --mdc-icon-font: "Material Symbols Outlined";
    // ← no @font-face here
}

In the Angular app and template-builder Storybook this is fine (those both load the font). In a standalone Stencil Storybook for dotcms-webcomponents itself (if one is ever added), icons would render as fallback/missing text. Low risk for the current setup, but worth noting for future isolated consumers.

4. label_important guard is now redundant (nit)

After this PR, label_important is not present in MaterialIconClasses, so the explicit this.value !== LABEL_IMPORTANT_ICON guard in dot-material-icon-picker.tsx:182 is technically redundant (the suggestionlist.includes(this.value) check would catch it). Keeping it is harmless — it preserves the reference to issue #22861 — but it's worth noting for anyone reading that code in the future.

5. Mixed <i> and <span> for icon elements (pre-existing, not introduced here)

Some templates use <i class="material-symbols-outlined"> while others use <span class="material-symbols-outlined">. The PR correctly preserves existing markup structure without changing element types. <span> is semantically more appropriate for ligature icons, but this is a pre-existing inconsistency outside this PR's scope.


Specific File Notes

core-web/libs/dotcms-scss/shared/_material-symbols-outlined.scss — Hardcoded /dotAdmin/assets/ path is correct for the production context and JSPs. If this SCSS is ever compiled in another context, the path would 404. Acceptable trade-off.

core-web/libs/template-builder/project.json — Both the build and storybook targets are correctly updated to point to material-symbols-outlined.css. Good.

core-web/libs/dotcms-webcomponents/stencil.config.ts — Adding globalStyle: 'src/global/global.scss' is the correct mechanism for Stencil global styles.

dotCMS/src/main/webapp/html/legacy_custom_field/legacy-custom-field.jsp — Inline @font-face updated correctly. The font-variation-settings are present on a single line here (not multi-line like in the SCSS), which is fine.

dotcms-block-editor.js — This is a compiled artifact. The change is a text substitution within a minified bundle, which is appropriate since the source is compiled Angular. Make sure the source SCSS/HTML also has the change (it does, per the other diffs).


Summary

The migration is thorough and well-reasoned. The main actionable item is re-running compodoc to fix the stale documentation.json snapshot. The bundle size increase is a known trade-off with a documented follow-up path. Everything else is either correct or pre-existing. Ready to merge once the stale docs entry is addressed.

… bundle

The webapp binary-field.js bundle still carried a scoped Angular rule
(.material-symbols-outlined[_ngcontent-%COMP%] { font-family: Material Icons })
from the previous suggestions.component.css. The rule's class selector
was swapped in the migration commit but the font-family reference was
missed — pointing at a font we've since deleted. Updates it to
'Material Symbols Outlined' so icons inside the block-editor suggestions
widget render until the bundle is regenerated from source.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread core-web/libs/dotcms-scss/shared/_material-symbols-outlined.scss
Comment thread core-web/libs/dotcms-scss/angular/styles.scss
@rjvelazco
Copy link
Copy Markdown
Member Author

@claude final review

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Apr 24, 2026

Claude finished @rjvelazco's task in 2m 9s —— View job


PR Final Review: Material Icons → Material Symbols Outlined

  • Read current state of previously-flagged files (documentation.json, binary-field.js)
  • Check git diff for any remaining issues
  • Review overall PR state and compile final findings

Final Review

What's been resolved since prior reviews

binary-field.js font-family patch (commit b78fa3af) — Correct. The scoped rule now reads font-family:'Material Symbols Outlined' and there are no remaining Material Icons references in binary-field.js. ✓

All source files are clean — Grep across .ts, .html, .scss, .css, .jsp, .vtl finds zero remaining material-icons class usages or MaterialIcons-Regular font references. The sweep is complete. ✓


Issues still outstanding

1. dotcms-block-editor.js — same scoped-CSS bug as binary-field.js, but NOT patched

binary-field.js was patched in b78fa3af, but dotcms-block-editor.js has the identical issue and was not patched:

.material-symbols-outlined[_ngcontent-%COMP%]{font-family:Material Icons;font-weight:400;...}

The class name was updated to material-symbols-outlined but font-family still says Material Icons. At runtime this means: the new class selector applies but the font loaded is the old (now-deleted) Material Icons TTF, so every icon rendered by that component in the block editor SPA would either fall back to system fonts or show as text glyphs.

This is a real visual regression, not just a stale artifact. binary-field.js was hand-patched for exactly this reason — dotcms-block-editor.js needs the same treatment.

Fix this →

2. documentation.json lines 161886 and 174526 — stale snapshot, flagged twice, still not fixed

Line 161886 — styleUrlsData for suggestions.component still contains:

.material-symbols-outlined {
    font-family: 'Material Icons';   /* ← wrong font-family! */
    ...
}

Line 174526 — defaultValue for a TypeScript function still contains @font-face { font-family: 'Material Icons'; src: url('/dotAdmin/assets/MaterialIcons-Regular.ttf') ... } referencing the deleted font file.

This has been called out in the two previous Claude reviews. The class name in the snapshot was updated but the font-family value was not, producing an internally inconsistent entry (class named for new font, body pointing to old font). The fix is re-running compodoc — the actual source file (suggestions.component.css) correctly removes the entire block, so regeneration would clean these entries automatically.

Fix this →


Summary

Item Status
All source .ts/.html/.scss/.css/.jsp/.vtl files clean
binary-field.js font-family patched
binary-field.js source/artifact divergence (known risk) ⚠️ acknowledged in PR description
dotcms-block-editor.js scoped font-family:Material Icons bug not fixed — visual regression
documentation.json stale entries (lines 161886, 174526) still unaddressed after 2 reviews

The dotcms-block-editor.js issue is the blocking one — it's a runtime visual regression in the block editor. The documentation.json entries are doc-only but have been pending for the full review cycle.

rjvelazco and others added 2 commits April 24, 2026 12:23
…les and docs

- dotcms-block-editor.js: same scoped-CSS bug as binary-field.js — the
  .material-symbols-outlined[_ngcontent-%COMP%] rule still carried
  `font-family: Material Icons` referencing the deleted font. Swapped to
  'Material Symbols Outlined' so icons inside the block-editor SPA
  render until the bundle is rebuilt from source.

- documentation.json: two committed compodoc entries still referenced
  `font-family: 'Material Icons'` and `MaterialIcons-Regular.ttf`
  (suggestions.component styleUrlsData + a defaultValue fixture string).
  Patched the three stale font-family lines and the two ttf src URLs
  in-place instead of regenerating, since a full compodoc regen produced
  340k lines of unrelated churn.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picked up by nx format:write via the pre-commit hook — drive-by
formatting, no behavior change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rjvelazco rjvelazco enabled auto-merge April 24, 2026 16:36
…value

When the class rename reformatter broke `<span class="material-symbols-outlined">{{ icon }}</span>`
onto three lines, textContent gained leading/trailing whitespace and the
test `expect(icon.nativeElement.textContent).toBe('web')` started failing.
Trimming the read is more robust against prettier-driven template
reformatting than fighting the formatter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rjvelazco rjvelazco added this pull request to the merge queue Apr 24, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Apr 24, 2026
@rjvelazco rjvelazco added this pull request to the merge queue Apr 24, 2026
Merged via the queue into main with commit 76fb121 Apr 24, 2026
50 checks passed
@rjvelazco rjvelazco deleted the issue-35447-replace-material-icons-with-material-symbols-in-core-web branch April 24, 2026 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI: Safe To Rollback Area : Backend PR changes Java/Maven backend code Area : Frontend PR changes Angular/TypeScript frontend code Area : SDK PR changes SDK libraries

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Replace Material Icons with Material Symbols in core-web

4 participants