Skip to content

Commit 072ad1d

Browse files
committed
feat(material/button): add support for tonal button
Adds support for the tonal button appearance from the spec. It can be enabled by setting `matButton="tonal"` on the button. Fixes #28809.
1 parent b088604 commit 072ad1d

22 files changed

+379
-72
lines changed
Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
section {
2-
display: table;
2+
display: flex;
3+
align-items: center;
34
}
45

56
.example-label {
6-
display: table-cell;
77
font-size: 14px;
8-
margin-left: 8px;
8+
margin: 0 16px 0 8px;
99
min-width: 120px;
1010
}
1111

1212
.example-button-row {
13-
display: table-cell;
1413
max-width: 600px;
1514
}
1615

@@ -23,9 +22,3 @@ section {
2322
justify-content: space-between;
2423
flex-wrap: wrap;
2524
}
26-
27-
.example-button-container {
28-
display: flex;
29-
justify-content: center;
30-
width: 140px;
31-
}

src/components-examples/material/button/button-overview/button-overview-example.html

Lines changed: 42 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<a matButton href="https://www.google.com/" target="_blank">Link</a>
77
</div>
88
</section>
9-
<mat-divider></mat-divider>
9+
<mat-divider/>
1010
<section>
1111
<div class="example-label">Elevated</div>
1212
<div class="example-button-row">
@@ -15,7 +15,7 @@
1515
<a matButton="elevated" href="https://www.google.com/" target="_blank">Link</a>
1616
</div>
1717
</section>
18-
<mat-divider></mat-divider>
18+
<mat-divider/>
1919
<section>
2020
<div class="example-label">Outlined</div>
2121
<div class="example-button-row">
@@ -24,16 +24,25 @@
2424
<a matButton="outlined" href="https://www.google.com/" target="_blank">Link</a>
2525
</div>
2626
</section>
27-
<mat-divider></mat-divider>
27+
<mat-divider/>
2828
<section>
2929
<div class="example-label">Filled</div>
3030
<div class="example-button-row">
31-
<button matButton="filled" >Basic</button>
32-
<button matButton="filled" disabled>Disabled</button>
31+
<button matButton="filled">Basic</button>
32+
<button matButton="filled" disabled>Disabled</button>
3333
<a matButton="filled" href="https://www.google.com/" target="_blank">Link</a>
3434
</div>
3535
</section>
36-
<mat-divider></mat-divider>
36+
<mat-divider/>
37+
<section>
38+
<div class="example-label">Tonal</div>
39+
<div class="example-button-row">
40+
<button matButton="tonal" >Basic</button>
41+
<button matButton="tonal" disabled>Disabled</button>
42+
<a matButton="tonal" href="https://www.google.com/" target="_blank">Link</a>
43+
</div>
44+
</section>
45+
<mat-divider/>
3746
<section>
3847
<div class="example-label">Icon</div>
3948
<div class="example-button-row">
@@ -47,64 +56,51 @@
4756
</div>
4857
</div>
4958
</section>
50-
<mat-divider></mat-divider>
59+
<mat-divider/>
5160
<section>
5261
<div class="example-label">Floating Action Button (FAB)</div>
5362
<div class="example-button-row">
5463
<div class="example-flex-container">
55-
<div class="example-button-container">
56-
<button matFab aria-label="Example icon button with a delete icon">
57-
<mat-icon>delete</mat-icon>
58-
</button>
59-
</div>
60-
<div class="example-button-container">
61-
<button matFab disabled aria-label="Example icon button with a heart icon">
62-
<mat-icon>favorite</mat-icon>
63-
</button>
64-
</div>
64+
<button matFab aria-label="Example icon button with a delete icon">
65+
<mat-icon>delete</mat-icon>
66+
</button>
67+
<button matFab disabled aria-label="Example icon button with a heart icon">
68+
<mat-icon>favorite</mat-icon>
69+
</button>
6570
</div>
6671
</div>
6772
</section>
68-
<mat-divider></mat-divider>
73+
<mat-divider/>
6974
<section>
7075
<div class="example-label">Mini FAB</div>
7176
<div class="example-button-row">
7277
<div class="example-flex-container">
73-
<div class="example-button-container">
74-
<button matMiniFab aria-label="Example icon button with a menu icon">
75-
<mat-icon>menu</mat-icon>
76-
</button>
77-
</div>
78-
<div class="example-button-container">
79-
<button matMiniFab disabled aria-label="Example icon button with a home icon">
80-
<mat-icon>home</mat-icon>
81-
</button>
82-
</div>
78+
<button matMiniFab aria-label="Example icon button with a menu icon">
79+
<mat-icon>menu</mat-icon>
80+
</button>
81+
<button matMiniFab disabled aria-label="Example icon button with a home icon">
82+
<mat-icon>home</mat-icon>
83+
</button>
8384
</div>
8485
</div>
8586
</section>
87+
<mat-divider/>
8688
<section>
8789
<div class="example-label">Extended FAB</div>
8890
<div class="example-button-row">
8991
<div class="example-flex-container">
90-
<div class="example-button-container">
91-
<button matFab extended>
92-
<mat-icon>favorite</mat-icon>
93-
Basic
94-
</button>
95-
</div>
96-
<div class="example-button-container">
97-
<button matFab extended disabled>
98-
<mat-icon>favorite</mat-icon>
99-
Disabled
100-
</button>
101-
</div>
102-
<div class="example-button-container">
103-
<a matFab extended routerLink=".">
104-
<mat-icon>favorite</mat-icon>
105-
Link
106-
</a>
107-
</div>
92+
<button matFab extended>
93+
<mat-icon>favorite</mat-icon>
94+
Basic
95+
</button>
96+
<button matFab extended disabled>
97+
<mat-icon>favorite</mat-icon>
98+
Disabled
99+
</button>
100+
<a matFab extended routerLink=".">
101+
<mat-icon>favorite</mat-icon>
102+
Link
103+
</a>
108104
</div>
109105
</div>
110106
</section>

src/dev-app/button/button-demo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,5 @@ export class ButtonDemo {
4949
toggleDisable = false;
5050
tooltipText = 'This is a button tooltip!';
5151
disabledInteractive = false;
52-
appearances: MatButtonAppearance[] = ['text', 'elevated', 'outlined', 'filled'];
52+
appearances: MatButtonAppearance[] = ['text', 'elevated', 'outlined', 'filled', 'tonal'];
5353
}

src/material/button/_button-theme.scss

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
@use '../core/tokens/m2/mat/protected-button' as tokens-mat-protected-button;
1212
@use '../core/tokens/m2/mdc/text-button' as tokens-mdc-text-button;
1313
@use '../core/tokens/m2/mat/text-button' as tokens-mat-text-button;
14+
@use '../core/tokens/m2/mat/tonal-button' as tokens-mat-tonal-button;
1415
@use '../core/style/sass-utils';
1516

1617
@mixin _text-button-variant($theme, $palette) {
@@ -81,6 +82,15 @@
8182
@include token-utils.create-token-values(tokens-mat-outlined-button.$prefix, $mat-tokens);
8283
}
8384

85+
@mixin _tonal-button-variant($theme, $palette) {
86+
@include token-utils.create-token-values(tokens-mat-tonal-button.$prefix, if(
87+
$palette,
88+
tokens-mat-tonal-button.private-get-color-palette-color-tokens($theme, $palette),
89+
tokens-mat-tonal-button.get-color-tokens($theme)
90+
));
91+
}
92+
93+
8494
@mixin _theme-from-tokens($tokens, $options...) {
8595
@include validation.selector-defined(
8696
'Calls to Angular Material theme mixins with an M3 theme must be wrapped in a selector'
@@ -125,6 +135,11 @@
125135
tokens-mat-outlined-button.$prefix,
126136
$options...
127137
);
138+
$mat-tonal-button-tokens: token-utils.get-tokens-for(
139+
$tokens,
140+
tokens-mat-tonal-button.$prefix,
141+
$options...
142+
);
128143

129144
@include token-utils.create-token-values(tokens-mdc-text-button.$prefix, $mdc-text-button-tokens);
130145
@include token-utils.create-token-values(
@@ -152,6 +167,10 @@
152167
tokens-mat-outlined-button.$prefix,
153168
$mat-outlined-button-tokens
154169
);
170+
@include token-utils.create-token-values(
171+
tokens-mat-tonal-button.$prefix,
172+
$mat-tonal-button-tokens
173+
);
155174
}
156175

157176
/// Outputs base theme styles (styles not dependent on the color, typography, or density settings)
@@ -195,6 +214,10 @@
195214
tokens-mat-outlined-button.$prefix,
196215
tokens-mat-outlined-button.get-unthemable-tokens()
197216
);
217+
@include token-utils.create-token-values(
218+
tokens-mat-tonal-button.$prefix,
219+
tokens-mat-tonal-button.get-unthemable-tokens()
220+
);
198221
}
199222
}
200223
}
@@ -211,6 +234,7 @@
211234
@include sass-utils.current-selector-or-root() {
212235
@include _text-button-variant($theme, null);
213236
@include _filled-button-variant($theme, null);
237+
@include _tonal-button-variant($theme, null);
214238
@include _protected-button-variant($theme, null);
215239
@include _outlined-button-variant($theme, null);
216240
}
@@ -270,6 +294,20 @@
270294
@include _outlined-button-variant($theme, warn);
271295
}
272296
}
297+
298+
.mat-tonal-button {
299+
&.mat-primary {
300+
@include _tonal-button-variant($theme, primary);
301+
}
302+
303+
&.mat-accent {
304+
@include _tonal-button-variant($theme, accent);
305+
}
306+
307+
&.mat-warn {
308+
@include _tonal-button-variant($theme, warn);
309+
}
310+
}
273311
}
274312
}
275313

@@ -313,6 +351,10 @@
313351
tokens-mat-outlined-button.$prefix,
314352
tokens-mat-outlined-button.get-typography-tokens($theme)
315353
);
354+
@include token-utils.create-token-values(
355+
tokens-mat-tonal-button.$prefix,
356+
tokens-mat-tonal-button.get-typography-tokens($theme)
357+
);
316358
}
317359
}
318360
}
@@ -357,6 +399,10 @@
357399
tokens-mat-outlined-button.$prefix,
358400
tokens-mat-outlined-button.get-density-tokens($theme)
359401
);
402+
@include token-utils.create-token-values(
403+
tokens-mat-tonal-button.$prefix,
404+
tokens-mat-tonal-button.get-density-tokens($theme)
405+
);
360406
}
361407
}
362408
}
@@ -371,6 +417,7 @@
371417
$mat-protected-button-tokens: tokens-mat-protected-button.get-token-slots();
372418
$mdc-text-button-tokens: tokens-mdc-text-button.get-token-slots();
373419
$mat-text-button-tokens: tokens-mat-text-button.get-token-slots();
420+
$mat-tonal-button-tokens: tokens-mat-tonal-button.get-token-slots();
374421

375422
@return (
376423
(
@@ -413,6 +460,11 @@
413460
tokens: $mat-text-button-tokens,
414461
prefix: 'text-',
415462
),
463+
(
464+
namespace: tokens-mat-tonal-button.$prefix,
465+
tokens: $mat-tonal-button-tokens,
466+
prefix: 'tonal-',
467+
),
416468
);
417469
}
418470

src/material/button/button-base.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import {_CdkPrivateStyleLoader} from '@angular/cdk/private';
2828
* Possible appearances for a `MatButton`.
2929
* See https://m3.material.io/components/buttons/overview
3030
*/
31-
export type MatButtonAppearance = 'text' | 'filled' | 'elevated' | 'outlined';
31+
export type MatButtonAppearance = 'text' | 'filled' | 'elevated' | 'outlined' | 'tonal';
3232

3333
/** Object that can be used to configure the default options for the button component. */
3434
export interface MatButtonConfig {

src/material/button/button-high-contrast.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
.mat-mdc-unelevated-button:not(.mdc-button--outlined),
55
.mat-mdc-raised-button:not(.mdc-button--outlined),
66
.mat-mdc-outlined-button:not(.mdc-button--outlined),
7+
.mat-mdc-button-base.mat-tonal-button,
78
.mat-mdc-icon-button.mat-mdc-icon-button,
89
.mat-mdc-outlined-button .mdc-button__ripple {
910
@include cdk.high-contrast {

src/material/button/button.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@ There are several button variants, each applied as an attribute:
2020
Additionally, the `matButton` has several appearances that can be set using the `matButton`
2121
attribute, for example `matButton="outlined"`:
2222

23-
2423
| Appearance | Description |
2524
|--------------|----------------------------------------------------------------------------------|
26-
| `text` | Default appearance. Does not have a background until the user interacts with it. |
27-
| `elevated` | Has a background color, elevation and rounded corners. |
28-
| `filled` | Has a flat appearance with rounded corners and no elevation. |
29-
| `outlined` | Has an outline, rounded corners and a transparent background. |
25+
| `text` | Default appearance. Text buttons are used for the lowest priority actions, especially when presenting multiple options. |
26+
| `filled` | High-emphasis buttons used for final or unblocking actions in a flow, such as saving or confirming. |
27+
| `tonal` | Medium-emphasis buttons often used for final or unblocking actions in a flow, but with less visual emphasis than a filled button. |
28+
| `outlined` | Medium-emphasis buttons often used for actions that need attention but aren't the primary action. |
29+
| `elevated` | Medium-emphasis buttons often used when a button requires visual separation from a patterned background. |
3030

3131

3232
### Extended FAB buttons

0 commit comments

Comments
 (0)