Button
Material Expressive Button with size, shape, and toggle variations. Supports both the .mat-exp-button CSS class approach and the [matExpButton] directive.
import { MatExpButton } from '@ngm-dev/mat-exp';Pre-requisites
Make sure either you have included mat-exp-all-styles, mat-exp-all-buttons-styles or mat-exp-button-styles in your global SCSS styles.
@use '@ngm-dev/mat-exp' as mat-exp;
html {
@include mat-exp.mat-exp-all-styles();
}
or
@use '@ngm-dev/mat-exp' as mat-exp;
html {
@include mat-exp.mat-exp-all-buttons-styles();
}
or
@use '@ngm-dev/mat-exp' as mat-exp;
html {
@include mat-exp.mat-exp-button-styles();
}
Usage
The styles for Material Expressive Button can be applied in two ways:
- Using the
.mat-exp-buttonclass with thedata-*attributes - Using the
directivematExpButton
Using the .mat-exp-button class with the data-\* attributes
import { MatButton } from '@angular/material/button';
@Component({
selector: 'app-root',
imports: [MatButton],
template: `
<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>
`,
})
export class App {}
Using the matExpButton directive
If you do not want to use data-* attributes and the .mat-exp-button class and want full type safety, you can use matExpButton
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 {}
Supported Variations
Mat Expressive Button supports the following variations:
- Size:
xs,s,m,l,xl - Shape:
round,square - Toggle:
selected,unselected - State:
pressed(:activepseudo-selector)
Toggle Behavior
Mat Expressive Button supports a toggle state (selected / unselected), but toggling on click
is only automatic inside a <mat-exp-button-group>
Standalone toggle buttons (outside a <mat-exp-button-group>toggle on click. This
is intentional: a lone button's click handler only has one consumer to satisfy, so the library leaves the state
transition up to you rather than guessing what a click should mean. Two-way bind toggle and
flip it yourself in your own (click) handler:
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');
}
Inside a MatExpButtonGrouptoggle for its
projected buttons based on the group's single-/multi-select state, and a manual click handler
would fight the group's own state management.
Shape Morph
Mat Expressive Button supports this shape morphing by default.
Pressed State
According to Material 3 Design System Expressive guidelines, when pressed, buttons can morph to become more square. Both round and square buttons should have the same pressed shape.
When selected
In addition to changing shape when pressed, toggle buttons also change the resting shape from round (unselected) to square (selected).
If the resting unselected shape is square, the selected shape should be round.
Accessibility
The shape-morph transition (border-radius, padding-left/padding-right, box-shadow) automatically stops under prefers-reduced-motion: reduce — Angular Material's own matButton host, which matExpButton
Playground
API
Data Attributes with .mat-exp-button class
Use these data-* attributes with the .mat-exp-button class to style the Angular Material Button component:
| Attribute | Default | Possible values |
|---|---|---|
data-size |
s |
xs, s, m, l, xl |
data-shape |
round |
round, square |
data-toggle |
unselected |
selected, unselected |
`MatExpButton`
Standalone directive, selector [matExpButton], exported as matExpButton
You can view the generated API for MatExpButton
Host
| Attribute / binding | Value |
|---|---|
data-size |
From size() input |
data-shape |
From shape() input |
data-toggle |
From toggle() input |
data-menu-open |
true when a [matMenuTriggerFor] on the same host has its menu open |
aria-pressed |
'true' / 'false' derived from toggle(); omitted entirely when toggle() is undefined |
class |
mat-exp-button |
(click) |
Delegates the click to the parent MatExpButtonGroup |
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
size |
MatExpButtonSize |
's' |
Size of the button. |
shape |
MatExpButtonShape |
'round' |
Shape of the button. |
toggle |
MatExpButtonToggle | undefined |
undefined |
Toggle state. Only auto-managed inside a MatExpButtonGroup |
value |
unknown |
undefined |
Value read by a parent MatExpButtonGroup |
size, shape, toggle, and value are all declared with model(), so they're two-way bindable (e.g. [(size)]="mySize").
Types:
–MatExpButtonSize'xs' | 's' | 'm' | 'l' | 'xl' –MatExpButtonShape'round' | 'square' –MatExpButtonToggle'selected' | 'unselected'
Note
MatExpButtonappearance / disabled accessors that read and write the underlying Angular Material matButton directive's own appearance / disabled inputs directly — bind those through matButton as usual (e.g. matButton="tonal", [disabled]).
Options and provider
`MatExpButtonOptions`
interface MatExpButtonOptions {
readonly size?: MatExpButtonSize;
readonly shape?: MatExpButtonShape;
readonly toggle?: MatExpButtonToggle;
}
`MAT_EXP_BUTTON_DEFAULT_OPTIONS`
Default object used when no provider overrides values:
size: 's'shape: 'round'
`MAT_EXP_BUTTON_OPTIONS`
InjectionToken for the resolved options object; used internally by the directive.
`provideMatExpButtonOptions`
import { provideMatExpButtonOptions } from '@ngm-dev/mat-exp';
export const appConfig: ApplicationConfig = {
providers: [
provideMatExpButtonOptions({
size: 'm',
shape: 'square',
}),
],
};
You may pass a partial static object or a factory () => Partial<MatExpButtonOptions>.
Styling
Usage
@use '@ngm-dev/mat-exp' as mat-exp;
html {
@include mat-exp.mat-exp-button-styles($options);
}
Options
| Option | Type | Default | Description |
|---|---|---|---|
skip-html-element-styles |
boolean |
false |
If true, the mixin won't apply styles to the underlying HTML elements. |
sizes |
list of 'xs' | 's' | 'm' | 'l' | 'xl' |
null (all sizes emitted) |
Restricts the emitted CSS to only the given sizes. Use this to cut the CSS payload when your app only uses a subset of sizes — see |
`skip-html-element-styles`
Setting this to true means the following won't work as expected:
- Icon sizes
- Shape morphing
@use '@ngm-dev/mat-exp' as mat-exp;
html {
@include mat-exp.mat-exp-button-styles(
(
skip-html-element-styles: true,
)
);
}
`sizes`
Drops the rest of the size × shape × state × toggle combination matrix at compile time.
@use '@ngm-dev/mat-exp' as mat-exp;
html {
@include mat-exp.mat-exp-button-styles(
(
sizes: ('s', 'm'),
)
);
}