ui-ux-consultant-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/ui-ux-consultant/SKILL.md +844 -0
- package/assets/ui-ux-consultant/references/accessibility.md +175 -0
- package/assets/ui-ux-consultant/references/alt-libraries.md +90 -0
- package/assets/ui-ux-consultant/references/animations.md +448 -0
- package/assets/ui-ux-consultant/references/catalog/colors.md +91 -0
- package/assets/ui-ux-consultant/references/catalog/fonts.md +363 -0
- package/assets/ui-ux-consultant/references/catalog/products.md +340 -0
- package/assets/ui-ux-consultant/references/catalog/styles.md +165 -0
- package/assets/ui-ux-consultant/references/components.md +1116 -0
- package/assets/ui-ux-consultant/references/patterns.md +600 -0
- package/assets/ui-ux-consultant/references/performance.md +198 -0
- package/assets/ui-ux-consultant/references/stacks/astro.md +382 -0
- package/assets/ui-ux-consultant/references/stacks/flutter.md +308 -0
- package/assets/ui-ux-consultant/references/stacks/html-tailwind.md +415 -0
- package/assets/ui-ux-consultant/references/stacks/jetpack-compose.md +333 -0
- package/assets/ui-ux-consultant/references/stacks/laravel.md +521 -0
- package/assets/ui-ux-consultant/references/stacks/nextjs.md +275 -0
- package/assets/ui-ux-consultant/references/stacks/nuxt-ui.md +384 -0
- package/assets/ui-ux-consultant/references/stacks/nuxtjs.md +264 -0
- package/assets/ui-ux-consultant/references/stacks/react-native.md +346 -0
- package/assets/ui-ux-consultant/references/stacks/react.md +268 -0
- package/assets/ui-ux-consultant/references/stacks/shadcn.md +485 -0
- package/assets/ui-ux-consultant/references/stacks/svelte.md +429 -0
- package/assets/ui-ux-consultant/references/stacks/swiftui.md +336 -0
- package/assets/ui-ux-consultant/references/stacks/threejs.md +366 -0
- package/assets/ui-ux-consultant/references/stacks/vue.md +272 -0
- package/assets/ui-ux-consultant/references/theming.md +701 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/package.json +51 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
# Angular Material 3 Theming Guide
|
|
2
|
+
|
|
3
|
+
Comprehensive reference for theming Angular Material 3 applications. Covers the M3 theming architecture, complete setup, dark mode, typography, design token overrides, density, and custom brand colors.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. M3 Theming Architecture
|
|
8
|
+
|
|
9
|
+
Angular Material 3 theming operates across three layers:
|
|
10
|
+
|
|
11
|
+
| Layer | Controls | API |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| **Color** | Primary, secondary, tertiary, neutral, error palettes | `color:` key in `define-theme()` |
|
|
14
|
+
| **Typography** | Font families, weights, and the 15-role type scale | `typography:` key in `define-theme()` |
|
|
15
|
+
| **Density** | Component spacing and size compactness | `density:` key in `define-theme()` |
|
|
16
|
+
|
|
17
|
+
**How it works:**
|
|
18
|
+
1. `mat.define-theme()` computes a complete M3 theme object from your configuration.
|
|
19
|
+
2. `mat.all-component-themes($theme)` (or individual `mat.*-theme()` mixins) emit CSS custom properties (`--mat-*`) scoped to the selector where you include them.
|
|
20
|
+
3. Every Material component reads those CSS custom properties at runtime — no Sass variables leak into component styles.
|
|
21
|
+
|
|
22
|
+
This means you can:
|
|
23
|
+
- Override any token by setting `--mat-*` in CSS without touching Sass.
|
|
24
|
+
- Scope a theme to a CSS class (e.g., `.dark-theme`) and toggle it dynamically.
|
|
25
|
+
- Apply different densities per section of the UI.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. Complete Theme Setup
|
|
30
|
+
|
|
31
|
+
### Install Dependencies
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
ng add @angular/material
|
|
35
|
+
# or manual:
|
|
36
|
+
npm install @angular/material @angular/cdk
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### `styles.scss` — Full Setup
|
|
40
|
+
|
|
41
|
+
```scss
|
|
42
|
+
@use '@angular/material' as mat;
|
|
43
|
+
|
|
44
|
+
// ─── Step 1: Include core styles once at root ───────────────────────────────
|
|
45
|
+
// Emits baseline resets and typography utilities. Must be called exactly once.
|
|
46
|
+
@include mat.core();
|
|
47
|
+
|
|
48
|
+
// ─── Step 2: Define your theme ──────────────────────────────────────────────
|
|
49
|
+
$my-theme: mat.define-theme((
|
|
50
|
+
color: (
|
|
51
|
+
theme-type: light, // 'light' | 'dark'
|
|
52
|
+
primary: mat.$azure-palette, // Main brand color (buttons, links, focus rings)
|
|
53
|
+
tertiary: mat.$orange-palette, // CTA / accent color (FAB, selected states)
|
|
54
|
+
// 'secondary' defaults to a neutral tonal palette — usually leave unset
|
|
55
|
+
),
|
|
56
|
+
typography: (
|
|
57
|
+
brand-family: 'Inter, sans-serif', // Display, Headline, Title roles
|
|
58
|
+
plain-family: 'Inter, sans-serif', // Body, Label roles
|
|
59
|
+
bold-weight: 700,
|
|
60
|
+
medium-weight: 500,
|
|
61
|
+
regular-weight: 400,
|
|
62
|
+
),
|
|
63
|
+
density: (
|
|
64
|
+
scale: 0, // 0 = default; -1 = compact; -2 = very compact; -3 = minimum
|
|
65
|
+
),
|
|
66
|
+
));
|
|
67
|
+
|
|
68
|
+
// ─── Step 3: Apply theme to all components ──────────────────────────────────
|
|
69
|
+
html {
|
|
70
|
+
@include mat.all-component-themes($my-theme);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── Alternatively: apply only to components you use (smaller CSS output) ───
|
|
74
|
+
// html {
|
|
75
|
+
// @include mat.core-theme($my-theme);
|
|
76
|
+
// @include mat.button-theme($my-theme);
|
|
77
|
+
// @include mat.form-field-theme($my-theme);
|
|
78
|
+
// @include mat.input-theme($my-theme);
|
|
79
|
+
// @include mat.select-theme($my-theme);
|
|
80
|
+
// @include mat.dialog-theme($my-theme);
|
|
81
|
+
// @include mat.snack-bar-theme($my-theme);
|
|
82
|
+
// @include mat.table-theme($my-theme);
|
|
83
|
+
// @include mat.paginator-theme($my-theme);
|
|
84
|
+
// @include mat.card-theme($my-theme);
|
|
85
|
+
// @include mat.toolbar-theme($my-theme);
|
|
86
|
+
// @include mat.sidenav-theme($my-theme);
|
|
87
|
+
// @include mat.list-theme($my-theme);
|
|
88
|
+
// @include mat.tabs-theme($my-theme);
|
|
89
|
+
// @include mat.progress-bar-theme($my-theme);
|
|
90
|
+
// @include mat.progress-spinner-theme($my-theme);
|
|
91
|
+
// @include mat.checkbox-theme($my-theme);
|
|
92
|
+
// @include mat.radio-theme($my-theme);
|
|
93
|
+
// @include mat.slide-toggle-theme($my-theme);
|
|
94
|
+
// @include mat.chips-theme($my-theme);
|
|
95
|
+
// @include mat.badge-theme($my-theme);
|
|
96
|
+
// @include mat.icon-theme($my-theme);
|
|
97
|
+
// @include mat.tooltip-theme($my-theme);
|
|
98
|
+
// @include mat.menu-theme($my-theme);
|
|
99
|
+
// @include mat.datepicker-theme($my-theme);
|
|
100
|
+
// @include mat.autocomplete-theme($my-theme);
|
|
101
|
+
// @include mat.stepper-theme($my-theme);
|
|
102
|
+
// @include mat.expansion-theme($my-theme);
|
|
103
|
+
// @include mat.tree-theme($my-theme);
|
|
104
|
+
// @include mat.bottom-sheet-theme($my-theme);
|
|
105
|
+
// }
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### `angular.json` — Register the stylesheet
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"projects": {
|
|
113
|
+
"my-app": {
|
|
114
|
+
"architect": {
|
|
115
|
+
"build": {
|
|
116
|
+
"options": {
|
|
117
|
+
"styles": ["src/styles.scss"]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### `index.html` — Icon font
|
|
127
|
+
|
|
128
|
+
```html
|
|
129
|
+
<!-- Material Symbols (M3, variable font — recommended) -->
|
|
130
|
+
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" rel="stylesheet" />
|
|
131
|
+
|
|
132
|
+
<!-- If using a Google Font for typography, add it here too -->
|
|
133
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet" />
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## 3. Available M3 Color Palettes
|
|
139
|
+
|
|
140
|
+
All built-in palettes ship with `@angular/material`. Each generates a full M3 tonal palette (10 steps from 0–100 in HCT color space).
|
|
141
|
+
|
|
142
|
+
| Palette Variable | Color Family | Best For |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `mat.$red-palette` | Red | Destructive actions, error states, alerts |
|
|
145
|
+
| `mat.$orange-palette` | Orange | CTA buttons, energy, warmth, food apps |
|
|
146
|
+
| `mat.$yellow-palette` | Yellow | Warnings, highlights |
|
|
147
|
+
| `mat.$green-palette` | Green | Success states, health, sustainability, finance |
|
|
148
|
+
| `mat.$teal-palette` | Teal | Healthcare, fintech, calm productivity |
|
|
149
|
+
| `mat.$cyan-palette` | Cyan | Tech, data, modern SaaS |
|
|
150
|
+
| `mat.$azure-palette` | Blue (lighter) | SaaS, productivity, trust |
|
|
151
|
+
| `mat.$blue-palette` | Blue (deeper) | Finance, enterprise, authority |
|
|
152
|
+
| `mat.$violet-palette` | Purple | Creative tools, premium, AI |
|
|
153
|
+
| `mat.$magenta-palette` | Pink/Magenta | Consumer, playful, fashion |
|
|
154
|
+
|
|
155
|
+
**Usage tip:** Set `primary` to your main brand color. Set `tertiary` to a complementary accent used for FABs, selected chips, and highlighted states. Never set all three (primary, secondary, tertiary) to the same palette — it will look flat.
|
|
156
|
+
|
|
157
|
+
```scss
|
|
158
|
+
// Example: Healthcare app
|
|
159
|
+
$health-theme: mat.define-theme((
|
|
160
|
+
color: (
|
|
161
|
+
theme-type: light,
|
|
162
|
+
primary: mat.$teal-palette,
|
|
163
|
+
tertiary: mat.$green-palette,
|
|
164
|
+
),
|
|
165
|
+
));
|
|
166
|
+
|
|
167
|
+
// Example: Creative / AI app
|
|
168
|
+
$creative-theme: mat.define-theme((
|
|
169
|
+
color: (
|
|
170
|
+
theme-type: light,
|
|
171
|
+
primary: mat.$violet-palette,
|
|
172
|
+
tertiary: mat.$magenta-palette,
|
|
173
|
+
),
|
|
174
|
+
));
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 4. Dark Mode Implementation
|
|
180
|
+
|
|
181
|
+
### Option A: CSS Class Toggle (Recommended)
|
|
182
|
+
|
|
183
|
+
Allows runtime switching without page reload. Works with SSR.
|
|
184
|
+
|
|
185
|
+
```scss
|
|
186
|
+
// styles.scss
|
|
187
|
+
$light-theme: mat.define-theme((
|
|
188
|
+
color: (theme-type: light, primary: mat.$azure-palette)
|
|
189
|
+
));
|
|
190
|
+
|
|
191
|
+
$dark-theme: mat.define-theme((
|
|
192
|
+
color: (theme-type: dark, primary: mat.$azure-palette)
|
|
193
|
+
));
|
|
194
|
+
|
|
195
|
+
html {
|
|
196
|
+
@include mat.all-component-themes($light-theme);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Override colors when .dark-theme class is on html or body
|
|
200
|
+
.dark-theme {
|
|
201
|
+
@include mat.all-component-colors($dark-theme);
|
|
202
|
+
// Note: use all-component-colors (not all-component-themes) to avoid
|
|
203
|
+
// re-emitting typography and density tokens unnecessarily.
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
// theme.service.ts
|
|
209
|
+
import { Injectable, signal, effect } from '@angular/core';
|
|
210
|
+
|
|
211
|
+
@Injectable({ providedIn: 'root' })
|
|
212
|
+
export class ThemeService {
|
|
213
|
+
readonly isDark = signal(
|
|
214
|
+
window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
constructor() {
|
|
218
|
+
// Persist preference
|
|
219
|
+
const saved = localStorage.getItem('theme');
|
|
220
|
+
if (saved) this.isDark.set(saved === 'dark');
|
|
221
|
+
|
|
222
|
+
// Apply on change
|
|
223
|
+
effect(() => {
|
|
224
|
+
const dark = this.isDark();
|
|
225
|
+
document.documentElement.classList.toggle('dark-theme', dark);
|
|
226
|
+
localStorage.setItem('theme', dark ? 'dark' : 'light');
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
toggle() {
|
|
231
|
+
this.isDark.update(v => !v);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
```html
|
|
237
|
+
<!-- Theme toggle button in toolbar -->
|
|
238
|
+
<button mat-icon-button (click)="themeService.toggle()"
|
|
239
|
+
[attr.aria-label]="themeService.isDark() ? 'Switch to light mode' : 'Switch to dark mode'">
|
|
240
|
+
<mat-icon>{{ themeService.isDark() ? 'light_mode' : 'dark_mode' }}</mat-icon>
|
|
241
|
+
</button>
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Option B: CSS Media Query (System preference only)
|
|
245
|
+
|
|
246
|
+
```scss
|
|
247
|
+
// styles.scss
|
|
248
|
+
html {
|
|
249
|
+
@include mat.all-component-themes($light-theme);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
@media (prefers-color-scheme: dark) {
|
|
253
|
+
html {
|
|
254
|
+
@include mat.all-component-colors($dark-theme);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Option C: Separate stylesheets (lazy-loaded)
|
|
260
|
+
|
|
261
|
+
For very large apps where dark mode CSS size matters:
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// In app bootstrap or a service
|
|
265
|
+
function loadDarkTheme() {
|
|
266
|
+
const link = document.createElement('link');
|
|
267
|
+
link.rel = 'stylesheet';
|
|
268
|
+
link.href = 'dark-theme.css'; // Built as separate stylesheet
|
|
269
|
+
document.head.appendChild(link);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 5. Typography Scale
|
|
276
|
+
|
|
277
|
+
Angular Material 3 defines 15 typographic roles. Apply them as CSS classes or use the Sass typography functions.
|
|
278
|
+
|
|
279
|
+
| Role | CSS Class | Typical Size | Usage |
|
|
280
|
+
|---|---|---|---|
|
|
281
|
+
| Display Large | `.mat-display-large` | 57px | Marketing hero headlines |
|
|
282
|
+
| Display Medium | `.mat-display-medium` | 45px | Large section titles |
|
|
283
|
+
| Display Small | `.mat-display-small` | 36px | Feature section titles |
|
|
284
|
+
| Headline Large | `.mat-headline-large` | 32px | Page H1 |
|
|
285
|
+
| Headline Medium | `.mat-headline-medium` | 28px | Section H2 |
|
|
286
|
+
| Headline Small | `.mat-headline-small` | 24px | Card or panel H2 |
|
|
287
|
+
| Title Large | `.mat-title-large` | 22px | Dialog titles, drawer headers |
|
|
288
|
+
| Title Medium | `.mat-title-medium` | 16px | List item primary text |
|
|
289
|
+
| Title Small | `.mat-title-small` | 14px | Chip labels, tab labels |
|
|
290
|
+
| Body Large | `.mat-body-large` | 16px | Primary body copy |
|
|
291
|
+
| Body Medium | `.mat-body-medium` | 14px | Secondary body, descriptions |
|
|
292
|
+
| Body Small | `.mat-body-small` | 12px | Captions, metadata |
|
|
293
|
+
| Label Large | `.mat-label-large` | 14px | Button text (built-in) |
|
|
294
|
+
| Label Medium | `.mat-label-medium` | 12px | Form field labels |
|
|
295
|
+
| Label Small | `.mat-label-small` | 11px | Helper text, overlines |
|
|
296
|
+
|
|
297
|
+
**Usage in templates:**
|
|
298
|
+
|
|
299
|
+
```html
|
|
300
|
+
<h1 class="mat-display-small">Welcome Back</h1>
|
|
301
|
+
<h2 class="mat-headline-medium">Recent Activity</h2>
|
|
302
|
+
<p class="mat-body-large">Your account summary for this month.</p>
|
|
303
|
+
<span class="mat-body-small mat-hint">Last updated 2 minutes ago</span>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Customizing the type scale in your theme:**
|
|
307
|
+
|
|
308
|
+
```scss
|
|
309
|
+
$my-theme: mat.define-theme((
|
|
310
|
+
typography: (
|
|
311
|
+
brand-family: '"Playfair Display", serif', // Display, Headline roles
|
|
312
|
+
plain-family: '"Inter", sans-serif', // Body, Label, Title roles
|
|
313
|
+
bold-weight: 700,
|
|
314
|
+
medium-weight: 500,
|
|
315
|
+
regular-weight: 400,
|
|
316
|
+
),
|
|
317
|
+
));
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Applying typography separately** (when you want to update fonts without re-emitting colors):
|
|
321
|
+
|
|
322
|
+
```scss
|
|
323
|
+
html {
|
|
324
|
+
@include mat.all-component-typographies($my-theme);
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## 6. CSS Custom Properties (Design Token Overrides)
|
|
331
|
+
|
|
332
|
+
Angular Material emits hundreds of `--mat-*` custom properties. Override them directly in CSS for fine-grained control without touching Sass. This is the recommended approach for one-off adjustments.
|
|
333
|
+
|
|
334
|
+
**Token naming pattern:** `--mat-{component}-{slot}`
|
|
335
|
+
|
|
336
|
+
### App-level tokens
|
|
337
|
+
|
|
338
|
+
```scss
|
|
339
|
+
html {
|
|
340
|
+
// Background and surface colors
|
|
341
|
+
--mat-app-background-color: #F8FAFC;
|
|
342
|
+
--mat-app-on-background-color: #1E293B;
|
|
343
|
+
--mat-app-surface-color: #FFFFFF;
|
|
344
|
+
--mat-app-on-surface-color: #1E293B;
|
|
345
|
+
}
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Button tokens
|
|
349
|
+
|
|
350
|
+
```scss
|
|
351
|
+
html {
|
|
352
|
+
// Filled button
|
|
353
|
+
--mat-filled-button-container-color: #2563EB;
|
|
354
|
+
--mat-filled-button-label-text-color: #FFFFFF;
|
|
355
|
+
--mat-filled-button-container-shape: 8px; // Override pill shape
|
|
356
|
+
|
|
357
|
+
// Outlined button
|
|
358
|
+
--mat-outlined-button-outline-color: #CBD5E1;
|
|
359
|
+
|
|
360
|
+
// Text button
|
|
361
|
+
--mat-text-button-label-text-color: #2563EB;
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
### Form field tokens
|
|
366
|
+
|
|
367
|
+
```scss
|
|
368
|
+
html {
|
|
369
|
+
--mat-form-field-container-height: 48px;
|
|
370
|
+
--mat-form-field-container-vertical-padding: 12px;
|
|
371
|
+
--mat-outlined-form-field-outline-color: #CBD5E1;
|
|
372
|
+
--mat-outlined-form-field-focus-outline-color: #2563EB;
|
|
373
|
+
--mat-form-field-label-text-size: 14px;
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Card tokens
|
|
378
|
+
|
|
379
|
+
```scss
|
|
380
|
+
html {
|
|
381
|
+
--mat-card-elevated-container-color: #FFFFFF;
|
|
382
|
+
--mat-card-elevated-container-elevation: 1;
|
|
383
|
+
--mat-card-outlined-container-color: #FFFFFF;
|
|
384
|
+
--mat-card-outlined-outline-color: #E2E8F0;
|
|
385
|
+
--mat-card-title-text-size: 18px;
|
|
386
|
+
}
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
### Table tokens
|
|
390
|
+
|
|
391
|
+
```scss
|
|
392
|
+
html {
|
|
393
|
+
--mat-table-background-color: #FFFFFF;
|
|
394
|
+
--mat-table-header-headline-color: #64748B;
|
|
395
|
+
--mat-table-header-headline-size: 12px;
|
|
396
|
+
--mat-table-header-headline-weight: 600;
|
|
397
|
+
--mat-table-row-item-label-text-color: #1E293B;
|
|
398
|
+
--mat-table-row-item-outline-color: #F1F5F9;
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
### Toolbar tokens
|
|
403
|
+
|
|
404
|
+
```scss
|
|
405
|
+
html {
|
|
406
|
+
--mat-toolbar-container-background-color: #FFFFFF;
|
|
407
|
+
--mat-toolbar-container-text-color: #1E293B;
|
|
408
|
+
}
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Dialog tokens
|
|
412
|
+
|
|
413
|
+
```scss
|
|
414
|
+
html {
|
|
415
|
+
--mat-dialog-container-color: #FFFFFF;
|
|
416
|
+
--mat-dialog-container-elevation: 3;
|
|
417
|
+
--mat-dialog-container-shape: 16px;
|
|
418
|
+
}
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### Snackbar tokens
|
|
422
|
+
|
|
423
|
+
```scss
|
|
424
|
+
html {
|
|
425
|
+
--mat-snack-bar-button-color: #93C5FD; // Action button color in dark snackbar
|
|
426
|
+
--mdc-snackbar-container-color: #1E293B;
|
|
427
|
+
--mdc-snackbar-supporting-text-color: #F8FAFC;
|
|
428
|
+
}
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
**How to find token names:** Open DevTools, inspect a Material component, and look for `--mat-*` properties in the computed styles. The Angular Material source also documents tokens per component at `https://material.angular.io`.
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## 7. Component-Level Color Overrides
|
|
436
|
+
|
|
437
|
+
Use the `color` input on individual components to apply the primary, accent (tertiary), or warn color from your theme.
|
|
438
|
+
|
|
439
|
+
```html
|
|
440
|
+
<!-- Buttons -->
|
|
441
|
+
<button mat-flat-button color="primary">Primary Action</button>
|
|
442
|
+
<button mat-flat-button color="accent">Accent (Tertiary)</button>
|
|
443
|
+
<button mat-flat-button color="warn">Destructive</button>
|
|
444
|
+
|
|
445
|
+
<!-- Progress indicators -->
|
|
446
|
+
<mat-progress-bar color="primary" mode="indeterminate" />
|
|
447
|
+
<mat-progress-spinner color="accent" mode="indeterminate" diameter="40" />
|
|
448
|
+
|
|
449
|
+
<!-- Form controls -->
|
|
450
|
+
<mat-checkbox color="primary" [formControl]="ctrl">Agree</mat-checkbox>
|
|
451
|
+
<mat-slide-toggle color="primary" [formControl]="ctrl">Enable</mat-slide-toggle>
|
|
452
|
+
<mat-radio-button color="primary" value="a">Option A</mat-radio-button>
|
|
453
|
+
|
|
454
|
+
<!-- Toolbar (sets background from palette) -->
|
|
455
|
+
<mat-toolbar color="primary">App Name</mat-toolbar>
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**M3 note:** `color="accent"` maps to the tertiary palette in M3 (not a separate "accent" concept). `color="warn"` maps to the error palette.
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 8. Density
|
|
463
|
+
|
|
464
|
+
Density scale controls the minimum height and padding of interactive components. Useful for data-dense admin UIs.
|
|
465
|
+
|
|
466
|
+
| Scale | Effect | Use Case |
|
|
467
|
+
|---|---|---|
|
|
468
|
+
| `0` | Default M3 sizing | Consumer apps, landing pages |
|
|
469
|
+
| `-1` | Slightly compact | Productivity tools |
|
|
470
|
+
| `-2` | Compact | Admin dashboards |
|
|
471
|
+
| `-3` | Very compact (minimum) | Data grids, developer tools |
|
|
472
|
+
|
|
473
|
+
### Global density
|
|
474
|
+
|
|
475
|
+
```scss
|
|
476
|
+
$compact-theme: mat.define-theme((
|
|
477
|
+
color: (theme-type: light, primary: mat.$azure-palette),
|
|
478
|
+
density: (scale: -2),
|
|
479
|
+
));
|
|
480
|
+
|
|
481
|
+
html {
|
|
482
|
+
@include mat.all-component-themes($compact-theme);
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### Scoped density (recommended for admin panels)
|
|
487
|
+
|
|
488
|
+
Apply compact density only to specific sections, keeping content areas readable:
|
|
489
|
+
|
|
490
|
+
```scss
|
|
491
|
+
// Global theme at default density
|
|
492
|
+
html {
|
|
493
|
+
@include mat.all-component-themes($default-theme);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
// Compact density only inside .data-table-section
|
|
497
|
+
$compact-theme: mat.define-theme((
|
|
498
|
+
color: (theme-type: light, primary: mat.$azure-palette),
|
|
499
|
+
density: (scale: -2),
|
|
500
|
+
));
|
|
501
|
+
|
|
502
|
+
.data-table-section {
|
|
503
|
+
@include mat.table-density($compact-theme);
|
|
504
|
+
@include mat.paginator-density($compact-theme);
|
|
505
|
+
@include mat.form-field-density($compact-theme);
|
|
506
|
+
@include mat.button-density($compact-theme);
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### Per-component density mixins
|
|
511
|
+
|
|
512
|
+
```scss
|
|
513
|
+
// Apply density to individual component types
|
|
514
|
+
@include mat.button-density($compact-theme);
|
|
515
|
+
@include mat.form-field-density($compact-theme);
|
|
516
|
+
@include mat.table-density($compact-theme);
|
|
517
|
+
@include mat.paginator-density($compact-theme);
|
|
518
|
+
@include mat.list-density($compact-theme);
|
|
519
|
+
@include mat.checkbox-density($compact-theme);
|
|
520
|
+
@include mat.radio-density($compact-theme);
|
|
521
|
+
@include mat.slide-toggle-density($compact-theme);
|
|
522
|
+
@include mat.select-density($compact-theme);
|
|
523
|
+
@include mat.autocomplete-density($compact-theme);
|
|
524
|
+
@include mat.datepicker-density($compact-theme);
|
|
525
|
+
@include mat.tabs-density($compact-theme);
|
|
526
|
+
@include mat.stepper-density($compact-theme);
|
|
527
|
+
@include mat.expansion-density($compact-theme);
|
|
528
|
+
@include mat.toolbar-density($compact-theme);
|
|
529
|
+
@include mat.tree-density($compact-theme);
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
---
|
|
533
|
+
|
|
534
|
+
## 9. Custom Color Palette (Brand Colors)
|
|
535
|
+
|
|
536
|
+
When your brand color isn't in the built-in palettes, generate an M3 tonal palette from it.
|
|
537
|
+
|
|
538
|
+
### Option A: Material Theme Builder (No-code)
|
|
539
|
+
|
|
540
|
+
1. Go to https://m3.material.io/theme-builder
|
|
541
|
+
2. Enter your brand hex color.
|
|
542
|
+
3. Export as CSS or Web (tokens).
|
|
543
|
+
4. Paste the generated `--md-sys-color-*` custom properties into your `styles.scss`.
|
|
544
|
+
|
|
545
|
+
```scss
|
|
546
|
+
// Paste generated tokens directly:
|
|
547
|
+
html {
|
|
548
|
+
--md-sys-color-primary: #6366F1;
|
|
549
|
+
--md-sys-color-on-primary: #FFFFFF;
|
|
550
|
+
--md-sys-color-primary-container: #E0E7FF;
|
|
551
|
+
--md-sys-color-on-primary-container: #1E1B4B;
|
|
552
|
+
/* ... all generated tokens ... */
|
|
553
|
+
}
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
### Option B: `@material/material-color-utilities` (Programmatic)
|
|
557
|
+
|
|
558
|
+
Generates the full tonal palette at runtime from a source color. Useful for user-customizable themes.
|
|
559
|
+
|
|
560
|
+
```bash
|
|
561
|
+
npm install @material/material-color-utilities
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
```typescript
|
|
565
|
+
// theme-generator.service.ts
|
|
566
|
+
import {
|
|
567
|
+
argbFromHex,
|
|
568
|
+
themeFromSourceColor,
|
|
569
|
+
applyTheme,
|
|
570
|
+
hexFromArgb
|
|
571
|
+
} from '@material/material-color-utilities';
|
|
572
|
+
|
|
573
|
+
@Injectable({ providedIn: 'root' })
|
|
574
|
+
export class ThemeGeneratorService {
|
|
575
|
+
|
|
576
|
+
applyBrandColor(hexColor: string, isDark = false) {
|
|
577
|
+
const argb = argbFromHex(hexColor);
|
|
578
|
+
const theme = themeFromSourceColor(argb);
|
|
579
|
+
|
|
580
|
+
applyTheme(theme, {
|
|
581
|
+
target: document.documentElement,
|
|
582
|
+
isDark,
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// Get specific tonal values from a color
|
|
587
|
+
getPalette(hexColor: string) {
|
|
588
|
+
const theme = themeFromSourceColor(argbFromHex(hexColor));
|
|
589
|
+
const { primary } = theme.palettes;
|
|
590
|
+
return {
|
|
591
|
+
tone10: hexFromArgb(primary.tone(10)),
|
|
592
|
+
tone20: hexFromArgb(primary.tone(20)),
|
|
593
|
+
tone40: hexFromArgb(primary.tone(40)),
|
|
594
|
+
tone80: hexFromArgb(primary.tone(80)),
|
|
595
|
+
tone90: hexFromArgb(primary.tone(90)),
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
```
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
// In a component or app init
|
|
603
|
+
readonly #themeGen = inject(ThemeGeneratorService);
|
|
604
|
+
|
|
605
|
+
// Apply a custom brand color on startup
|
|
606
|
+
ngOnInit() {
|
|
607
|
+
this.#themeGen.applyBrandColor('#6366F1', false);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Let users pick their brand color
|
|
611
|
+
onColorChange(hex: string) {
|
|
612
|
+
this.#themeGen.applyBrandColor(hex, this.isDark());
|
|
613
|
+
}
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### Option C: Sass map (static custom palette)
|
|
617
|
+
|
|
618
|
+
Define tonal values manually as a Sass map for use with `mat.define-theme()`:
|
|
619
|
+
|
|
620
|
+
```scss
|
|
621
|
+
// _custom-palette.scss
|
|
622
|
+
// Generate tones using https://m3.material.io/theme-builder or material-color-utilities
|
|
623
|
+
$indigo-palette: (
|
|
624
|
+
0: #000000,
|
|
625
|
+
10: #1B0060,
|
|
626
|
+
20: #2D0086,
|
|
627
|
+
25: #360099,
|
|
628
|
+
30: #4000AD,
|
|
629
|
+
35: #4A12BB,
|
|
630
|
+
40: #5424C9,
|
|
631
|
+
50: #6D3DE5,
|
|
632
|
+
60: #8A5EFF,
|
|
633
|
+
70: #A882FF,
|
|
634
|
+
80: #C5A8FF,
|
|
635
|
+
90: #E6DEFF,
|
|
636
|
+
95: #F4EEFF,
|
|
637
|
+
98: #FDF7FF,
|
|
638
|
+
99: #FFFBFF,
|
|
639
|
+
100: #FFFFFF,
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
// styles.scss
|
|
643
|
+
@use './custom-palette' as custom;
|
|
644
|
+
|
|
645
|
+
$my-theme: mat.define-theme((
|
|
646
|
+
color: (
|
|
647
|
+
theme-type: light,
|
|
648
|
+
primary: custom.$indigo-palette,
|
|
649
|
+
),
|
|
650
|
+
));
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## 10. Multi-Theme Support
|
|
656
|
+
|
|
657
|
+
For applications requiring per-tenant or per-section theming:
|
|
658
|
+
|
|
659
|
+
```scss
|
|
660
|
+
// Theme A: Default (blue)
|
|
661
|
+
$theme-a: mat.define-theme((color: (theme-type: light, primary: mat.$azure-palette)));
|
|
662
|
+
|
|
663
|
+
// Theme B: Green (e.g., a different product)
|
|
664
|
+
$theme-b: mat.define-theme((color: (theme-type: light, primary: mat.$green-palette)));
|
|
665
|
+
|
|
666
|
+
// Theme C: Dark violet
|
|
667
|
+
$theme-c: mat.define-theme((color: (theme-type: dark, primary: mat.$violet-palette)));
|
|
668
|
+
|
|
669
|
+
html {
|
|
670
|
+
@include mat.all-component-themes($theme-a); // Default
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
[data-theme="b"] {
|
|
674
|
+
@include mat.all-component-colors($theme-b);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
[data-theme="c"] {
|
|
678
|
+
@include mat.all-component-colors($theme-c);
|
|
679
|
+
}
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
```typescript
|
|
683
|
+
// Apply theme to root element
|
|
684
|
+
setTheme(theme: 'a' | 'b' | 'c') {
|
|
685
|
+
document.documentElement.dataset['theme'] = theme;
|
|
686
|
+
}
|
|
687
|
+
```
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
## 11. Common Theming Mistakes
|
|
692
|
+
|
|
693
|
+
| Mistake | Fix |
|
|
694
|
+
|---|---|
|
|
695
|
+
| Calling `@include mat.core()` more than once | Call it once in `styles.scss`, never in component styles |
|
|
696
|
+
| Using `mat.define-light-theme()` (v14 API) | Use `mat.define-theme()` with `theme-type: light` |
|
|
697
|
+
| Importing `MatNativeDateModule` and `MatMomentDateModule` both | Pick one date adapter and import it once in app config |
|
|
698
|
+
| Setting `color="primary"` on `mat-icon` to get brand color | Use `--mat-icon-color` token or a CSS class instead |
|
|
699
|
+
| Overriding `--mdc-*` tokens directly | Prefer `--mat-*` tokens; MDC tokens are lower-level and less stable |
|
|
700
|
+
| Not including component themes (components look unstyled in M3) | Ensure `mat.all-component-themes()` is called or each component's theme mixin is included |
|
|
701
|
+
| Forgetting `@include mat.core-theme($theme)` when using selective includes | `core-theme` is required alongside component themes — it emits ripple and option styles |
|
package/dist/index.d.ts
ADDED