--- title: "Introducing Mat Expressive: Material 3 Expressive for Angular Material" author: "Dharmen Shah" published: "2026-07-31T17:46:36.657Z" updated: "2026-09-01T14:40:00.180Z" url: "https://zyvop.com/introducing-mat-expressive-material-3-expressive-for-angular-material-yyzk8" canonical: "https://expressive.angular-material.dev/blogs/announcement" tags: ["SCSS","angular","Material Design","TypeScript","Angular Material","Material Expressive"] --- # Introducing Mat Expressive: Material 3 Expressive for Angular Material Mat Expressive layers Material 3 Expressive — spring motion, shape morphing, and bold sizing — on top of Angular Material, without forking or replacing it. ![Cover image]() ## What is Mat Expressive? Mat Expressive is a library of styles, directives, and a few new components that sit **on top of** Angular Material. It's not a fork and not a replacement — you keep using `MatButton`, `MatFab`, and the rest of Angular Material as-is. Mat Expressive layers M3 Expressive behavior onto them. Concretely, it gives you three things: - **Styles** — SCSS mixins that restyle existing Angular Material components using Material's own [component token overrides]() and CSS variables, so they match M3 Expressive. - **Directives** — for the cases styling alone can't reach (things like shape morphing on press, which need actual behavior, not just CSS). - **New components** — for patterns M3 Expressive defines that Angular Material doesn't have a component for at all (loading indicators, FAB menus, split buttons). Under the hood, motion is powered by GSAP spring physics, every animation respects `prefers-reduced-motion`, and the library is SSR-safe. ## Installation ```bash ng add @ngm-dev/mat-exp ``` The schematic wires up the package for you. From there, add the styles you need globally: ```scss // styles.scss @use '@ngm-dev/mat-exp' as mat-exp; html { @include mat-exp.mat-exp-button-styles(); } ``` ## A first component: the expressive button The clearest way to see what Mat Expressive does is the button. Angular Material already has `matButton` — Mat Expressive adds size, shape, and toggle variations on top of it, plus the shape-morph-on-press behavior from the M3 Expressive spec. You can opt in two ways. **Option 1 — CSS class + data attributes**, no extra imports beyond styles: ```xml ``` **Option 2 — the** `matExpButton` **directive**, if you want type safety and two-way bindable inputs: ```ts import { MatButton } from '@angular/material/button'; import { MatExpButton } from '@ngm-dev/mat-exp'; @Component({ selector: 'app-root', imports: [MatButton, MatExpButton], template: ` `, }) export class App {} ``` Both approaches give you the same variations: - **Size**: `xs`, `s`, `m`, `l`, `xl` - **Shape**: `round`, `square` - **Toggle**: `selected`, `unselected` - **State**: `pressed` (driven by the `:active` pseudo-selector) ## Shape morphing, and why it's a directive and not just CSS One of the defining traits of M3 Expressive buttons is that they morph shape when pressed — round buttons square off slightly, and both round and square buttons converge on the same pressed shape. Toggle buttons go further: the _resting_ shape itself changes between selected and unselected states. This is exactly the kind of thing that can't be pure CSS — it needs to read component state and react to it — which is why `matExpButton` exists as a directive rather than just a stylesheet. Accessibility is handled automatically here too: the shape-morph transition stops entirely under `prefers-reduced-motion: reduce`, because `matExpButton` piggybacks on Angular Material's own `matButton` host, which already detects the setting. ## Toggle state: a deliberate design choice If you've used a toggle button before, you might expect `toggle` to flip on click automatically. In Mat Expressive, it doesn't — unless the button lives inside a ``. For a standalone toggle button, the library leaves the click-to-state transition up to you: ```ts import { signal } from '@angular/core'; import { MatButton } from '@angular/material/button'; import { MatExpButton } from '@ngm-dev/mat-exp'; @Component({ selector: 'app-root', imports: [MatButton, MatExpButton], template: ` `, }) export class App { protected readonly favorited = model<'selected' | 'unselected'>('unselected'); } ``` This is intentional rather than an oversight: a lone button only has one consumer for its click event, so guessing what that click should mean would be presumptuous. Inside a `MatExpButtonGroup`, the group already owns selection state for its buttons — adding your own click handler there would fight it. ## Cutting the CSS payload By default, the style mixins emit CSS for every size × shape × state × toggle combination. If your app only ever uses two or three sizes, you don't need to ship the rest: ```scss @use '@ngm-dev/mat-exp' as mat-exp; html { @include mat-exp.mat-exp-button-styles( ( sizes: ('s', 'm'), ) ); } ``` There's also a `skip-html-element-styles` option if you don't want Mat Expressive touching the underlying Angular Material DOM elements at all — useful if you're worried about coupling to Angular Material's internal classes, at the cost of losing icon-size adjustments and shape morphing. ## What's included so far At launch, Mat Expressive covers: - **Buttons** — Button, Icon Button, Button Group, Split Button, FAB Menu - **Loading & Progress** — an M3 Expressive [loading indicator]() with GSAP spring motion More components are planned, following the same pattern: style what Angular Material already has, build what it doesn't. ## Try it ```bash ng add @ngm-dev/mat-exp ``` - 📖 Docs: [expressive.angular-material.dev]() - 💻 GitHub: [github.com/Angular-Material-Dev/mat-exp]() - 🐦 Follow along: [@ngMaterialDev]() It's MIT licensed and free. If you're building on Angular Material and want the M3 Expressive look — motion, shape morphing, and all — without hand-rolling it yourself, give it a try. Issues and feature requests are welcome on GitHub.