ZyVOP Logo
Content That Connects
SeriesAI NewsCategoriesWrite for Us
ZyVOP Logo
Content That Connects

Empowering developers and creators with cutting-edge insights, comprehensive tutorials, and innovative solutions for the digital future.

Content

  • Tags
  • Badges
  • Write Article
  • Newsletter

Company

  • About Us
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

© 2026 ZyVOP. Crafted with care for the developer community.

Made with ❤️ by the ZyVOP team
All systems operational
HomeNewsIntroducing Mat Expressive: Material 3 Expressive for Angular Material
News

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.

Dharmen Shah
Dharmen ShahFrontend developer
July 31, 2026
4 min read
1 views
Introducing Mat Expressive: Material 3 Expressive for Angular Material
#angular#Angular Material#TypeScript#SCSS#Material Design#Material Expressive
👍1

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

ng add @ngm-dev/mat-exp

The schematic wires up the package for you. From there, add the styles you need globally:

// 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:

<button matButton="elevated" class="mat-exp-button" data-size="xs" data-shape="square">
  Elevated
</button>
<button matButton="tonal" class="mat-exp-button" data-size="s">Tonal</button>

Option 2 — the matExpButton directive, if you want type safety and two-way bindable inputs:

import { MatButton } from '@angular/material/button';
import { MatExpButton } from '@ngm-dev/mat-exp';

@Component({
  selector: 'app-root',
  imports: [MatButton, MatExpButton],
  template: `
    <button matButton="elevated" size="xs" shape="square" matExpButton>Elevated</button>
    <button matButton="tonal" size="s" matExpButton>Tonal</button>
  `,
})
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 <mat-exp-button-group>.

For a standalone toggle button, the library leaves the click-to-state transition up to you:

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: `
    <button
      matButton="tonal"
      matExpButton
      [(toggle)]="favorited"
      (click)="favorited.set(favorited() === 'selected' ? 'unselected' : 'selected')"
    >
      Favorite
    </button>
  `,
})
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:

@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

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.

Dharmen Shah

Dharmen Shah

Frontend developer

Passionate developer sharing knowledge about modern web technologies and best practices.

Comments (0)

Login to post a comment.

Related Posts

Why I Validate Angular Compatibility Using the Published npm Package (Not the Source Code)

Most Angular libraries claim compatibility across multiple Angular versions—but how many actually verify it? Here's why I stopped testing my source code and started validating the packaged npm artifact that users really install.

Read article

Type-Safe React Architecture

I remember the exact moment I realized I couldn't go back. I had been writing TypeScript for a while, got used to it, and then joined a project that was pure Ja...

Read article

Starting a New React Project in 2026-2027: The Stack I Keep Coming Back To

I was three weeks into a new client engagement — a mid-sized insurance company building a policy administration CRM from scratch. No legacy code, no inherited d...

Read article

TypeScript in React: Patterns That Actually Matter

Six weeks into the insurance CRM project, we had a production incident. The backend team renamed a field — policy_number became policyNumber — as part of a snak...

Read article

Error Handling in React: What Users Should See When Things Break

The first serious error-handling conversation on the insurance CRM happened after a demo. We had built the policy detail page. It fetched the policy, loaded the...

Read article