Skip to content

Commit b722fcf

Browse files
authored
docs(material/theming): rewrite theming-your-components guide (#22465)
This change completely rewrites the theming-your-components guide to be more complete, correct, and concise. Summary of changes: * Start document with some explanatory content before diving into step-by-step tutorial. * Use new Sass `@use` API introduced in #22173 * Document (and expose) `get-color-config` and `get-typography-config`
1 parent 7d1963b commit b722fcf

File tree

2 files changed

+187
-97
lines changed

2 files changed

+187
-97
lines changed

guides/theming-your-components.md

Lines changed: 186 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,135 +1,224 @@
1-
# Theming your custom component with Angular Material's theming system
1+
# Theme your own components with Angular Material's theming system
22

3-
In order to style your own components with Angular Material's tooling, the component's styles must
4-
be defined with Sass.
3+
You can use Angular Material's Sass-based theming system for your own custom components.
54

6-
## 1. Define all color and typography styles in a "theme file" for the component
5+
## Reading style values from a theme
76

8-
First, create a Sass mixin that accepts an Angular Material color configuration and
9-
outputs the color-specific styles for the component. A color configuration is a Sass map.
7+
As described in the [theming guide][theme-map], a theme is a Sass map that contains style values to
8+
customize components. Angular Material provides APIs for reading values from this data structure.
9+
10+
[theme-map]: https://material.angular.io/guide/theming#themes
11+
12+
### Reading color values
13+
14+
To read color values from a theme, you can use the `get-color-config` Sass function. This function
15+
returns a Sass map containing the theme's primary, accent, and warn palettes, as well as a flag
16+
indicating whether dark mode is set.
1017

11-
For example, if building a custom carousel component:
1218
```scss
13-
// Import library functions for theme creation.
14-
@import '~@angular/material/theming';
15-
16-
@mixin candy-carousel-color($config-or-theme) {
17-
// Extract the color configuration in case a theme has been passed.
18-
// This allows consumers to either pass a theme object or a color configuration.
19-
$config: mat-get-color-config($config-or-theme);
20-
// Extract the palettes you need from the theme definition.
21-
$primary: map-get($config, primary);
22-
$accent: map-get($config, accent);
23-
24-
// Define any styles affected by the theme.
25-
.candy-carousel {
26-
// Use mat-color to extract individual colors from a palette.
27-
background-color: mat-color($primary);
28-
border-color: mat-color($accent, A400);
29-
}
30-
}
19+
@use 'sass:map';
20+
@use '~@angular/material' as mat;
21+
22+
$color-config: mat.get-color-config($theme);
23+
$primary-palette: map.get($color-config, 'primary');
24+
$accent-palette: map.get($color-config, 'accent');
25+
$warn-palette: map.get($color-config, 'warn');
26+
$is-dark-theme: map.get($color-config, 'is-dark');
3127
```
3228

33-
Second, create another Sass mixin that accepts an Angular Material typography configuration
34-
and outputs typographic styles. For example:
29+
See the [theming guide][theme-read-hues] for more information on reading hues from palettes.
30+
31+
[theme-read-hues]: https://material.angular.io/guide/theming#reading-hues-from-palettes
32+
33+
### Reading typography values
34+
35+
To read typography values from a theme, you can use the `get-typography-config` Sass function. See
36+
the [Typography guide][typography-config] for more information about the typography config data
37+
structure and for APIs for reading values from this config.
38+
39+
[typography-config]: https://material.angular.io/guide/typography#typography-config
3540

3641
```scss
37-
@mixin candy-carousel-typography($config-or-theme) {
38-
// Extract the typography configuration in case a theme has been passed.
39-
$config: mat-get-typography-config($config-or-theme);
40-
41-
.candy-carousel {
42-
font: {
43-
family: mat-font-family($config, body-1);
44-
size: mat-font-size($config, body-1);
45-
weight: mat-font-weight($config, body-1);
46-
}
47-
}
42+
@use '~@angular/material' as mat;
43+
44+
$typography-config: mat.get-typography-config($theme);
45+
$my-font-family: mat.font-family($typography-config);
46+
```
47+
48+
## Separating theme styles
49+
50+
Angular Material components each have a Sass file that defines mixins for customizing
51+
that component's color and typography. For example, `MatButton` has mixins for `button-color` and
52+
`button-typography`. Each mixin emits all color and typography styles for that component,
53+
respectively.
54+
55+
You can mirror this structure in your components by defining your own mixins. These mixins
56+
should accept an Angular Material theme, from which they can read color and typography values. You
57+
can then include these mixins in your application along with Angular Material's own mixins.
58+
59+
## Step-by-step example
60+
61+
To illustrate participation in Angular Material's theming system, we can look at an example of a
62+
custom carousel component. The carousel starts with a single file, `carousel.scss`, that contains
63+
structural, color, and typography styles. This file is included in the `styleUrls` of the component.
64+
65+
```scss
66+
// carousel.scss
67+
68+
.my-carousel {
69+
display: flex;
70+
font-family: serif;
71+
}
72+
73+
.my-carousel-button {
74+
border-radius: 50%;
75+
color: blue;
4876
}
4977
```
5078

51-
Finally, create a mixin that accepts an Angular Material theme, and delegates to the individual
52-
theming system mixins based on the configurations. A theme consists of configurations for
53-
individual theming systems (`color` and `typography`).
79+
### Step 1: Extract theme-based styles to a separate file
80+
81+
To change this file to participate in Angular Material's theming system, we split the styles into
82+
two files, with the color and typography styles moved into mixins. By convention, the new file
83+
name ends with `-theme`. Additionally, the file starts with an underscore (`_`), indicating that
84+
this is a Sass partial file. See the [Sass documentation][sass-partials] for more information about
85+
partial files.
86+
87+
[sass-partials]: https://sass-lang.com/guide#topic-4
88+
89+
```scss
90+
// carousel.scss
91+
92+
.my-carousel {
93+
display: flex;
94+
}
95+
96+
.my-carousel-button {
97+
border-radius: 50%;
98+
}
99+
```
54100

55101
```scss
56-
@mixin candy-carousel-theme($theme) {
57-
// Extracts the color and typography configurations from the theme.
58-
$color: mat-get-color-config($theme);
59-
$typography: mat-get-typography-config($theme);
60-
61-
// Do not generate styles if configurations for individual theming
62-
// systems have been explicitly set to `null`.
63-
@if $color != null {
64-
@include candy-carousel-color($color);
102+
// _carousel-theme.scss
103+
104+
@mixin color($theme) {
105+
.my-carousel-button {
106+
color: blue;
65107
}
66-
@if $typography != null {
67-
@include candy-carousel-typography($typography);
108+
}
109+
110+
@mixin typography($theme) {
111+
.my-carousel {
112+
font-family: serif;
68113
}
69114
}
70115
```
71116

72-
See the [typography guide](https://material.angular.io/guide/typography) for more information on
73-
typographic customization.
117+
### Step 2: Use values from the theme
74118

75-
## 2. Define all remaining styles in a normal component stylesheet
119+
Now that theme theme-based styles reside in mixins, we can extract the values we need from the
120+
theme passed into the mixins.
76121

77-
Define all styles unaffected by the theme in a separate file referenced directly in the component's
78-
`styleUrl`. This generally includes everything except for color and typography styles.
122+
```scss
123+
// _carousel-theme.scss
79124

125+
@use 'sass:map';
126+
@use '~@angular/material' as mat;
80127

81-
## 3. Include the theme mixin in your application
128+
@mixin color($theme) {
129+
// Get the color config from the theme.
130+
$color-config: mat.get-color-config($theme);
82131

83-
Use the Sass `@include` keyword to include a component's theme mixin wherever you're already
84-
including Angular Material's built-in theme mixins.
132+
// Get the primary color palette from the color-config.
133+
$primary-palette: map.get($color-config, 'primary');
85134

86-
```scss
87-
// Import library functions for theme creation.
88-
@import '~@angular/material/theming';
89-
90-
// Include non-theme styles for core.
91-
@include mat-core();
92-
93-
// Define your application's custom theme.
94-
$primary: mat-palette($mat-indigo);
95-
$accent: mat-palette($mat-pink, A200, A100, A400);
96-
$theme: mat-light-theme((
97-
color: (
98-
primary: $primary,
99-
accent: $accent,
100-
)
101-
));
135+
.my-carousel-button {
136+
// Read the 500 hue from the primary color palette.
137+
color: mat.get-color-from-palette($primary-palette, 500);
138+
}
139+
}
102140

103-
// Include theme styles for Angular Material components.
104-
@include angular-material-theme($theme);
141+
@mixin typography($theme) {
142+
// Get the typography config from the theme.
143+
$typography-config: mat.get-typography-config($theme);
105144

106-
// Include theme styles for your custom components.
107-
@include candy-carousel-theme($theme);
145+
.my-carousel {
146+
font-family: mat.font-family($typography-config);
147+
}
148+
}
108149
```
109150

151+
### Step 3: Add a theme mixin
110152

111-
## Note: using the `mat-color` function to extract colors from a palette
112-
113-
You can consume the theming functions and Material Design color palettes from
114-
`@angular/material/theming`. The `mat-color` Sass function extracts a specific color from a palette.
115-
For example:
153+
For convenience, we can add a `theme` mixin that includes both color and typography.
154+
This theme mixin should only emit the styles for each color and typography, respectively, if they
155+
have a config specified.
116156

117157
```scss
118-
// Import theming functions
119-
@import '~@angular/material/theming';
158+
// _carousel-theme.scss
159+
160+
@use 'sass:map';
161+
@use '~@angular/material' as mat;
120162

121-
.candy-carousel {
122-
// Get the default hue for a palette.
123-
color: mat-color($primary);
163+
@mixin color($theme) {
164+
// Get the color config from the theme.
165+
$color-config: mat.get-color-config($theme);
124166

125-
// Get a specific hue for a palette.
126-
// See https://material.io/archive/guidelines/style/color.html#color-color-palette for hues.
127-
background-color: mat-color($accent, 300);
167+
// Get the primary color palette from the color-config.
168+
$primary-palette: map.get($color-config, 'primary');
128169

129-
// Get a relative color for a hue ('lighter' or 'darker')
130-
outline-color: mat-color($accent, lighter);
170+
.my-carousel-button {
171+
// Read the 500 hue from the primary color palette.
172+
color: mat.get-color-from-palette($primary-palette, 500);
173+
}
174+
}
175+
176+
@mixin typography($theme) {
177+
// Get the typography config from the theme.
178+
$typography-config: mat.get-typography-config($theme);
179+
180+
.my-carousel {
181+
font-family: mat.font-family($typography-config);
182+
}
183+
}
184+
185+
@mixin theme($theme) {
186+
$color-config: mat.get-color-config($theme);
187+
@if $color-config != null {
188+
@include color($theme);
189+
}
131190

132-
// Get a contrast color for a hue by adding `-contrast` to any other key.
133-
border-color: mat-color($primary, '100-contrast');
191+
$typography-config: mat.get-typography-config($theme);
192+
@if $typography-config != null {
193+
@include typography($theme);
194+
}
134195
}
135196
```
197+
198+
### Step 4: Include the theme mixin in your application
199+
200+
Now that you've defined the carousel component's theme mixin, you can include this mixin along with
201+
the the other theme mixins in your application.
202+
203+
```scss
204+
@use '~@angular/material' as mat;
205+
@use './path/to/carousel-theme' as carousel;
206+
207+
@include mat.core();
208+
209+
$my-primary: mat.define-palette(mat.$indigo-palette, 500);
210+
$my-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
211+
212+
$my-theme: mat.define-light-theme((
213+
color: (
214+
primary: $my-primary,
215+
accent: $my-accent,
216+
),
217+
typography: mat.define-typography-config(
218+
$font-family: serif,
219+
);
220+
));
221+
222+
@include mat.all-component-themes($my-theme);
223+
@include carousel.theme($theme);
224+
```

src/material/_index.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Theming APIs
22
@forward './core/theming/theming' show define-light-theme, define-dark-theme,
33
define-palette, get-contrast-color-from-palette, get-color-from-palette,
4+
get-color-config, get-typography-config, get-density-config,
45
$theme-ignore-duplication-warnings;
56
@forward './core/theming/palette' show $red-palette, $pink-palette, $indigo-palette,
67
$purple-palette, $deep-purple-palette, $blue-palette, $light-blue-palette, $cyan-palette,

0 commit comments

Comments
 (0)