Architecture Note: Building a Custom Angular Material Theme
Define a palette once, include mat-core only, apply via angular-material-theme, and verify CSS output and contrast for accessible theming.
17 Apr 2026, 07:28 UTC

Problem
Angular Material applications often need a consistent visual identity across modules, lazy‑loaded routes, and server‑rendered pages. Without a deliberate theming strategy, duplicate style blocks increase bundle size and can cause visual mismatches.
Useful Takeaway
Define a single Material palette, build a light or dark theme with the official mixins, include mat-core once, and apply the theme through the angular-material-theme mixin in a global stylesheet. Verify the output with build‑time checks and contrast tests.
Requirements
- Angular CLI project with Angular Material >=15 installed.
- Access to the global stylesheet (usually
src/styles.scss) with write permission. - A build step that produces CSS (e.g.,
ng buildorng serve).
Minimal Suitable Design
- Define the palette in the stylesheet using
mat-palette. - Create a light or dark theme via
mat-light-themeormat-dark-theme. - Include
mat-coreexactly once to output base styles. - Apply the theme with the
angular-material-thememixin (or the version‑specificmat-all-component-themesif using v15+). - Optionally expose a runtime switch by toggling a class on
htmland using CSS‑variable based theming (requires v15+).
Trust / Data Boundaries
Theme values are compile‑time constants. If you allow end‑users to pick a theme, restrict the choice to a predefined list of palette names (e.g., 'indigo‑pink', 'purple‑green') and map those to pre‑computed SCSS variables. Never pass raw RGB strings directly into the SCSS without sanitisation, as that could inject arbitrary CSS.
Operational Checks
- After a build, inspect the generated CSS (e.g.,
dist/styles.css) to confirm thatmat-coreappears only once. - Use a contrast‑testing tool such as
axe-coreon a representative page to verify WCAG AA ratios for both light and dark variants. - For lazy‑loaded modules, verify that component styles reference the same CSS variables (look for
--mat-primaryetc.) in the dev‑tools. - If using runtime switching, reload the page and ensure the UI updates without a flash of unstyled content (FOUC).
Failure Modes
- Duplicate inclusion of
mat-corebloats the CSS and may cause selector specificity wars, leading to unexpected colour overrides. - Exposing arbitrary colour inputs without validation can break the theme or introduce CSS injection.
- Attempting runtime theming on Angular Material versions <15 will leave components styled with the compile‑time theme only, causing a mismatch.
- Missing contrast checks can produce inaccessible text‑background pairs, especially in dark mode.
Conditions That Would Change the Design
- Upgrade to Angular Material v15+ and desire to use CSS‑variable based theming – then replace the static
angular-material-thememixin with themat-color-configapproach and define variables on:root. - Introduce a user‑driven theme editor that allows arbitrary hue selection – then move theme generation to runtime (e.g., generate CSS variables on the fly) and enforce a sanitisation step.
- Require support for high‑contrast mode forced by the OS – then add a separate
mat-high-contrast-themeand switch based on a media query.
Practical Verification Steps
- Run
ng build --stats-json(requires read access to the project folder). - Open the generated
stats.jsonand locate theassetssection for the stylesheet; verify the size is reasonable and that themat-coreruleset appears only once (you can search for.mat‑coreor the comment/* mat‑core */). - Serve the build locally (
ng serve) and open Chrome DevTools → Sources → styles.css; search format-coreto confirm a single block. - Install
axe-corevia npm and runnpx axeagainst the served page; check that no contrast violations are reported for both themes. - If using runtime switching, toggle the theme class and observe that the computed background‑color of a
mat-toolbarchanges instantly without a blank flash.
Limitations
- The static theme approach requires a rebuild to change colours; it is not suitable for truly dynamic palettes without additional tooling.
- Runtime CSS‑variable theming increases the initial CSS size slightly and depends on browser support for custom properties (IE11 not supported).
- Theme customization exposed to end‑users must be strictly controlled; otherwise you risk delivering unsafe CSS to the client.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.