diff --git a/goldens/material/card/index.api.md b/goldens/material/card/index.api.md
index 345ac1081a53..5bcc72ee089b 100644
--- a/goldens/material/card/index.api.md
+++ b/goldens/material/card/index.api.md
@@ -32,7 +32,7 @@ export class MatCardActions {
}
// @public (undocumented)
-export type MatCardAppearance = 'outlined' | 'raised';
+export type MatCardAppearance = 'outlined' | 'raised' | 'filled';
// @public
export class MatCardAvatar {
diff --git a/src/components-examples/material/card/card-overview/card-overview-example.html b/src/components-examples/material/card/card-overview/card-overview-example.html
index 6805d4fb8214..e91eecb2db93 100644
--- a/src/components-examples/material/card/card-overview/card-overview-example.html
+++ b/src/components-examples/material/card/card-overview/card-overview-example.html
@@ -1,3 +1,11 @@
+
+ Elevated
+
+
- Simple card
+ Outlined
+
+
+ Filled
+
\ No newline at end of file
diff --git a/src/dev-app/card/BUILD.bazel b/src/dev-app/card/BUILD.bazel
index 8c8b14bf433c..5d420cda0d55 100644
--- a/src/dev-app/card/BUILD.bazel
+++ b/src/dev-app/card/BUILD.bazel
@@ -15,7 +15,7 @@ ng_project(
"//:node_modules/@angular/forms",
"//src/material/button",
"//src/material/card",
- "//src/material/checkbox",
+ "//src/material/radio",
],
)
diff --git a/src/dev-app/card/card-demo.html b/src/dev-app/card/card-demo.html
index a09abf454fc9..d4de4196bf48 100644
--- a/src/dev-app/card/card-demo.html
+++ b/src/dev-app/card/card-demo.html
@@ -1,5 +1,9 @@
- Use outlined cards
+
+ Raised
+ Outlined
+ Filled
+
diff --git a/src/dev-app/card/card-demo.scss b/src/dev-app/card/card-demo.scss
index 6038ba0385ae..945be0598362 100644
--- a/src/dev-app/card/card-demo.scss
+++ b/src/dev-app/card/card-demo.scss
@@ -16,3 +16,7 @@
text-transform: uppercase;
}
}
+
+mat-radio-group {
+ margin-bottom: 10px;
+}
diff --git a/src/dev-app/card/card-demo.ts b/src/dev-app/card/card-demo.ts
index 4db09dd68157..7202b53a81e1 100644
--- a/src/dev-app/card/card-demo.ts
+++ b/src/dev-app/card/card-demo.ts
@@ -10,14 +10,14 @@ import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/co
import {FormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
import {MatCardAppearance, MatCardModule} from '@angular/material/card';
-import {MatCheckboxModule} from '@angular/material/checkbox';
+import {MatRadioModule} from '@angular/material/radio';
@Component({
selector: 'card-demo',
templateUrl: 'card-demo.html',
styleUrl: 'card-demo.css',
encapsulation: ViewEncapsulation.None,
- imports: [MatCardModule, MatButtonModule, MatCheckboxModule, FormsModule],
+ imports: [MatCardModule, MatButtonModule, MatRadioModule, FormsModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CardDemo {
@@ -28,7 +28,4 @@ export class CardDemo {
As of some one gently rapping, rapping at my chamber door.
“’Tis some visitor,” I muttered, “tapping at my chamber door—
Only this and nothing more.”`;
- toggleAppearance() {
- this.appearance = this.appearance == 'raised' ? 'outlined' : 'raised';
- }
}
diff --git a/src/material/card/_card-theme.scss b/src/material/card/_card-theme.scss
index 41a8338648a1..3acc0358c741 100644
--- a/src/material/card/_card-theme.scss
+++ b/src/material/card/_card-theme.scss
@@ -8,6 +8,7 @@
@use '../core/tokens/m2/mat/card' as tokens-mat-card;
@use '../core/tokens/m2/mat/elevated-card' as tokens-mat-elevated-card;
@use '../core/tokens/m2/mat/outlined-card' as tokens-mat-outlined-card;
+@use '../core/tokens/m2/mat/filled-card' as tokens-mat-filled-card;
@mixin base($theme) {
@if inspection.get-theme-version($theme) == 1 {
@@ -22,6 +23,10 @@
tokens-mat-outlined-card.$prefix,
tokens-mat-outlined-card.get-unthemable-tokens()
);
+ @include token-utils.create-token-values-mixed(
+ tokens-mat-filled-card.$prefix,
+ tokens-mat-filled-card.get-unthemable-tokens()
+ );
@include token-utils.create-token-values-mixed(
tokens-mat-card.$prefix,
tokens-mat-card.get-unthemable-tokens()
@@ -43,6 +48,10 @@
tokens-mat-outlined-card.$prefix,
tokens-mat-outlined-card.get-color-tokens($theme)
);
+ @include token-utils.create-token-values-mixed(
+ tokens-mat-filled-card.$prefix,
+ tokens-mat-filled-card.get-color-tokens($theme)
+ );
@include token-utils.create-token-values-mixed(
tokens-mat-card.$prefix,
tokens-mat-card.get-color-tokens($theme)
@@ -64,6 +73,10 @@
tokens-mat-outlined-card.$prefix,
tokens-mat-outlined-card.get-typography-tokens($theme)
);
+ @include token-utils.create-token-values-mixed(
+ tokens-mat-filled-card.$prefix,
+ tokens-mat-filled-card.get-typography-tokens($theme)
+ );
@include token-utils.create-token-values-mixed(
tokens-mat-card.$prefix,
tokens-mat-card.get-typography-tokens($theme)
@@ -85,6 +98,10 @@
tokens-mat-outlined-card.$prefix,
tokens-mat-outlined-card.get-density-tokens($theme)
);
+ @include token-utils.create-token-values-mixed(
+ tokens-mat-filled-card.$prefix,
+ tokens-mat-filled-card.get-density-tokens($theme)
+ );
@include token-utils.create-token-values-mixed(
tokens-mat-card.$prefix,
tokens-mat-card.get-density-tokens($theme)
@@ -110,6 +127,11 @@
tokens: tokens-mat-outlined-card.get-token-slots(),
prefix: 'outlined-',
),
+ (
+ namespace: tokens-mat-filled-card.$prefix,
+ tokens: tokens-mat-filled-card.get-token-slots(),
+ prefix: 'filled-',
+ )
);
}
@@ -149,6 +171,10 @@
tokens-mat-outlined-card.$prefix,
map.get($tokens, tokens-mat-outlined-card.$prefix)
);
+ @include token-utils.create-token-values(
+ tokens-mat-filled-card.$prefix,
+ map.get($tokens, tokens-mat-filled-card.$prefix)
+ );
@include token-utils.create-token-values(
tokens-mat-card.$prefix,
map.get($tokens, tokens-mat-card.$prefix)
diff --git a/src/material/card/card.scss b/src/material/card/card.scss
index e392ffc162cc..82b654e6c394 100644
--- a/src/material/card/card.scss
+++ b/src/material/card/card.scss
@@ -2,6 +2,7 @@
@use '../core/tokens/m2/mat/card' as tokens-mat-card;
@use '../core/tokens/m2/mat/elevated-card' as tokens-mat-elevated-card;
@use '../core/tokens/m2/mat/outlined-card' as tokens-mat-outlined-card;
+@use '../core/tokens/m2/mat/filled-card' as tokens-mat-filled-card;
// Size of the `mat-card-header` region custom to Angular Material.
$mat-card-header-size: 40px !default;
@@ -68,6 +69,17 @@ $mat-card-default-padding: 16px !default;
}
}
+.mat-mdc-card-filled {
+ @include token-utils.use-tokens(
+ tokens-mat-filled-card.$prefix,
+ tokens-mat-filled-card.get-token-slots()
+ ) {
+ @include token-utils.create-token-slot(background-color, container-color);
+ @include token-utils.create-token-slot(border-radius, container-shape);
+ @include token-utils.create-token-slot(box-shadow, container-elevation);
+ }
+}
+
.mdc-card__media {
position: relative;
box-sizing: border-box;
diff --git a/src/material/card/card.ts b/src/material/card/card.ts
index 80c58b639d8b..a0197b3c48ca 100644
--- a/src/material/card/card.ts
+++ b/src/material/card/card.ts
@@ -16,7 +16,7 @@ import {
inject,
} from '@angular/core';
-export type MatCardAppearance = 'outlined' | 'raised';
+export type MatCardAppearance = 'outlined' | 'raised' | 'filled';
/** Object that can be used to configure the default options for the card module. */
export interface MatCardConfig {
@@ -41,6 +41,8 @@ export const MAT_CARD_CONFIG = new InjectionToken('MAT_CARD_CONFI
'class': 'mat-mdc-card mdc-card',
'[class.mat-mdc-card-outlined]': 'appearance === "outlined"',
'[class.mdc-card--outlined]': 'appearance === "outlined"',
+ '[class.mat-mdc-card-filled]': 'appearance === "filled"',
+ '[class.mdc-card--filled]': 'appearance === "filled"',
},
exportAs: 'matCard',
encapsulation: ViewEncapsulation.None,
diff --git a/src/material/core/tokens/m2/_index.scss b/src/material/core/tokens/m2/_index.scss
index b44a30b53f0c..42f540fd132e 100644
--- a/src/material/core/tokens/m2/_index.scss
+++ b/src/material/core/tokens/m2/_index.scss
@@ -7,6 +7,7 @@
@use './mat/text-button' as tokens-mat-text-button;
@use './mat/protected-button' as tokens-mat-protected-button;
@use './mat/filled-button' as tokens-mat-filled-button;
+@use './mat/filled-card' as tokens-mat-filled-card;
@use './mat/outlined-button' as tokens-mat-outlined-button;
@use './mat/dialog' as tokens-mat-dialog;
@use './mat/bottom-sheet' as tokens-mat-bottom-sheet;
@@ -114,6 +115,7 @@
_get-tokens-for-module($theme, tokens-mat-fab),
_get-tokens-for-module($theme, tokens-mat-fab-small),
_get-tokens-for-module($theme, tokens-mat-filled-button),
+ _get-tokens-for-module($theme, tokens-mat-filled-card),
_get-tokens-for-module($theme, tokens-mat-form-field),
_get-tokens-for-module($theme, tokens-mat-grid-list),
_get-tokens-for-module($theme, tokens-mat-icon-button),
diff --git a/src/material/core/tokens/m2/mat/_filled-card.scss b/src/material/core/tokens/m2/mat/_filled-card.scss
new file mode 100644
index 000000000000..0bccc53969a3
--- /dev/null
+++ b/src/material/core/tokens/m2/mat/_filled-card.scss
@@ -0,0 +1,50 @@
+@use '../../../style/elevation';
+@use '../../../theming/inspection';
+@use '../../../style/sass-utils';
+@use '../../token-definition';
+
+// The prefix used to generate the fully qualified name for tokens in this file.
+$prefix: (mat, filled-card);
+
+// Tokens that can't be configured through Angular Material's current theming API,
+// but may be in a future version of the theming API.
+//
+// Tokens that are available in MDC, but not used in Angular Material should be mapped to `null`.
+// `null` indicates that we are intentionally choosing not to emit a slot or value for the token in
+// our CSS.
+@function get-unthemable-tokens() {
+ @return (
+ container-shape: 4px,
+ );
+}
+
+// Tokens that can be configured through Angular Material's color theming API.
+@function get-color-tokens($theme) {
+ $elevation: inspection.get-theme-color($theme, foreground, elevation);
+
+ @return (
+ container-color: inspection.get-theme-color($theme, background, card),
+ container-elevation: elevation.get-box-shadow(0),
+ );
+}
+
+// Tokens that can be configured through Angular Material's typography theming API.
+@function get-typography-tokens($theme) {
+ @return ();
+}
+
+// Tokens that can be configured through Angular Material's density theming API.
+@function get-density-tokens($theme) {
+ @return ();
+}
+
+// Combines the tokens generated by the above functions into a single map with placeholder values.
+// This is used to create token slots.
+@function get-token-slots() {
+ @return sass-utils.deep-merge-all(
+ get-unthemable-tokens(),
+ get-color-tokens(token-definition.$placeholder-color-config),
+ get-typography-tokens(token-definition.$placeholder-typography-config),
+ get-density-tokens(token-definition.$placeholder-density-config)
+ );
+}
diff --git a/src/material/core/tokens/m3/_index.scss b/src/material/core/tokens/m3/_index.scss
index f6e664f48dc7..ea6c1e73aef9 100644
--- a/src/material/core/tokens/m3/_index.scss
+++ b/src/material/core/tokens/m3/_index.scss
@@ -16,6 +16,7 @@
@use './mat/fab';
@use './mat/fab-small';
@use './mat/filled-button';
+@use './mat/filled-card';
@use './mat/filled-text-field';
@use './mat/form-field';
@use './mat/full-pseudo-checkbox';
@@ -78,6 +79,7 @@
fab.get-tokens($systems, $exclude-hardcoded, $token-slots),
fab-small.get-tokens($systems, $exclude-hardcoded, $token-slots),
filled-button.get-tokens($systems, $exclude-hardcoded, $token-slots),
+ filled-card.get-tokens($systems, $exclude-hardcoded, $token-slots),
filled-text-field.get-tokens($systems, $exclude-hardcoded, $token-slots),
form-field.get-tokens($systems, $exclude-hardcoded, $token-slots),
full-pseudo-checkbox.get-tokens($systems, $exclude-hardcoded, $token-slots),
diff --git a/src/material/core/tokens/m3/mat/_filled-card.scss b/src/material/core/tokens/m3/mat/_filled-card.scss
new file mode 100644
index 000000000000..275c685859a8
--- /dev/null
+++ b/src/material/core/tokens/m3/mat/_filled-card.scss
@@ -0,0 +1,27 @@
+@use 'sass:map';
+@use '../../../style/elevation';
+@use '../../token-definition';
+
+// The prefix used to generate the fully qualified name for tokens in this file.
+$prefix: (mat, filled-card);
+
+/// Generates the tokens for MDC filled-card
+/// @param {Map} $systems The MDC system tokens
+/// @param {Boolean} $exclude-hardcoded Whether to exclude hardcoded token values
+/// @param {Map} $token-slots Possible token slots
+/// @return {Map} A set of tokens for the MDC filled-card
+@function get-tokens($systems, $exclude-hardcoded, $token-slots) {
+ $tokens: (
+ container-color: map.get($systems, md-sys-color, surface-container-highest),
+ container-elevation: map.get($systems, md-sys-elevation, level0),
+ container-shape: map.get($systems, md-sys-shape, corner-medium),
+ );
+
+ $elevation: map.get($tokens, container-elevation);
+
+ @if ($elevation != null) {
+ $tokens: map.set($tokens, container-elevation, elevation.get-box-shadow($elevation));
+ }
+
+ @return token-definition.namespace-tokens($prefix, $tokens, $token-slots);
+}