@stackific/md3 0.1.2 → 0.1.3
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/README.md +2499 -161
- package/dist/internal.md +274 -0
- package/dist/md3.css +1 -1
- package/dist/md3.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,38 +1,149 @@
|
|
|
1
1
|
# @stackific/md3
|
|
2
2
|
|
|
3
|
-
Material Design 3 framework
|
|
3
|
+
> Material Design 3 framework. Compiled CSS + plain-JS runtime. Drop into any HTML page; no framework required.
|
|
4
4
|
|
|
5
|
-
-
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- **Optional dynamic theming** from a hex / image / file via `material-dynamic-colors` (opt-in dependency).
|
|
5
|
+
- Light, dark, and OS-following `auto` modes — CSS-driven, no JS needed.
|
|
6
|
+
- 18 baked brand themes, swap with one attribute.
|
|
7
|
+
- Optional runtime theme generation from a hex / image / file (via `material-dynamic-colors`).
|
|
8
|
+
- Material Symbols icon fonts ship inside the CSS — no Google Fonts import.
|
|
10
9
|
|
|
11
10
|
---
|
|
12
11
|
|
|
13
|
-
##
|
|
12
|
+
## Table of contents
|
|
13
|
+
|
|
14
|
+
- [Install](#install)
|
|
15
|
+
- [Quick start](#quick-start)
|
|
16
|
+
- [Bootstrap](#bootstrap) — `data-theme`, `data-mode`, `data-ui`
|
|
17
|
+
- [Runtime API](#runtime-api) — `ui(...)`
|
|
18
|
+
- [Main layout](#main-layout)
|
|
19
|
+
- **Components**
|
|
20
|
+
- [Badge](#badge)
|
|
21
|
+
- [Button](#button)
|
|
22
|
+
- [Card](#card)
|
|
23
|
+
- [Checkbox](#checkbox)
|
|
24
|
+
- [Chip](#chip)
|
|
25
|
+
- [Container](#container)
|
|
26
|
+
- [Dialog](#dialog)
|
|
27
|
+
- [Divider](#divider)
|
|
28
|
+
- [Expansion](#expansion)
|
|
29
|
+
- [Field](#field) (Input · Select · Textarea · Search · Custom inputs)
|
|
30
|
+
- [Grid](#grid)
|
|
31
|
+
- [Header & Footer](#header--footer)
|
|
32
|
+
- [Icon](#icon)
|
|
33
|
+
- [Layout](#layout) (`.absolute` / `.fixed`)
|
|
34
|
+
- [List](#list)
|
|
35
|
+
- [Media](#media) (`<img>`, `<svg>`, `<video>`)
|
|
36
|
+
- [Menu](#menu)
|
|
37
|
+
- [Navigation](#navigation)
|
|
38
|
+
- [Overlay](#overlay)
|
|
39
|
+
- [Page](#page)
|
|
40
|
+
- [Progress](#progress)
|
|
41
|
+
- [Radio](#radio)
|
|
42
|
+
- [Shape](#shape)
|
|
43
|
+
- [Slider](#slider)
|
|
44
|
+
- [Snackbar](#snackbar)
|
|
45
|
+
- [Switch](#switch)
|
|
46
|
+
- [Table](#table)
|
|
47
|
+
- [Tabs](#tabs)
|
|
48
|
+
- [Tooltip](#tooltip)
|
|
49
|
+
- [Typography](#typography)
|
|
50
|
+
- **Helpers**
|
|
51
|
+
- [Alignments](#alignments)
|
|
52
|
+
- [Blurs](#blurs)
|
|
53
|
+
- [Color roles](#color-roles)
|
|
54
|
+
- [Directions](#directions)
|
|
55
|
+
- [Elevations](#elevations)
|
|
56
|
+
- [Forms](#forms-helpers) (border, round, corners, …)
|
|
57
|
+
- [Margins](#margins)
|
|
58
|
+
- [Opacities](#opacities)
|
|
59
|
+
- [Paddings](#paddings)
|
|
60
|
+
- [Positions](#positions)
|
|
61
|
+
- [Responsive](#responsive)
|
|
62
|
+
- [Ripples](#ripples)
|
|
63
|
+
- [Scrolls](#scrolls)
|
|
64
|
+
- [Shadows](#shadows)
|
|
65
|
+
- [Sizes](#sizes)
|
|
66
|
+
- [Spaces](#spaces)
|
|
67
|
+
- [Waves](#waves)
|
|
68
|
+
- [Zoom](#zoom)
|
|
69
|
+
- [Design tokens](#design-tokens)
|
|
70
|
+
- [Themes](#themes)
|
|
71
|
+
- [Theme & Mode selector](#theme-and-mode-selector)
|
|
72
|
+
- [Breakpoints](#breakpoints)
|
|
73
|
+
- [Repository](#repository)
|
|
14
74
|
|
|
15
|
-
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Install
|
|
78
|
+
|
|
79
|
+
**CDN** — paste into any HTML page:
|
|
80
|
+
|
|
81
|
+
```html
|
|
82
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stackific/md3/dist/md3.css">
|
|
83
|
+
<script type="module" src="https://cdn.jsdelivr.net/npm/@stackific/md3/dist/md3.js"></script>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**npm / pnpm / yarn:**
|
|
87
|
+
|
|
88
|
+
```sh
|
|
89
|
+
npm install @stackific/md3
|
|
90
|
+
# or: pnpm add @stackific/md3
|
|
91
|
+
# or: yarn add @stackific/md3
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```js
|
|
95
|
+
import "@stackific/md3"; // runtime, registers globalThis.ui
|
|
96
|
+
import "@stackific/md3/style"; // compiled CSS
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Local files** — download `dist/md3.css`, `dist/md3.js`, and the `dist/assets/*` they reference from the published package, then serve them from your own host:
|
|
100
|
+
|
|
101
|
+
```html
|
|
102
|
+
<link rel="stylesheet" href="/md3/md3.css">
|
|
103
|
+
<script type="module" src="/md3/md3.js"></script>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For Vite users, build with `assetsInlineLimit: 0` to keep the bundled CSS at its original size (otherwise the font files get inlined as data URIs).
|
|
107
|
+
|
|
108
|
+
**Optional — runtime theme generation from a hex / image / file:**
|
|
109
|
+
|
|
110
|
+
```sh
|
|
111
|
+
npm install material-dynamic-colors
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
import "material-dynamic-colors"; // once, at app entry
|
|
116
|
+
await ui("theme", "#1447E6");
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Without it, only baked-theme swaps and precomputed `{ light, dark }` objects work via `ui("theme", …)`.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## Quick start
|
|
16
124
|
|
|
17
125
|
```html
|
|
18
126
|
<!doctype html>
|
|
19
|
-
<html data-theme="stackific">
|
|
127
|
+
<html data-theme="stackific" data-mode="auto">
|
|
20
128
|
<head>
|
|
129
|
+
<meta charset="UTF-8">
|
|
130
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
21
131
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@stackific/md3/dist/md3.css">
|
|
22
132
|
<script type="module" src="https://cdn.jsdelivr.net/npm/@stackific/md3/dist/md3.js"></script>
|
|
133
|
+
<title>Hello M3</title>
|
|
23
134
|
</head>
|
|
24
135
|
<body>
|
|
25
136
|
<main class="responsive">
|
|
26
137
|
<h1>Hello, M3</h1>
|
|
27
|
-
<
|
|
28
|
-
|
|
29
|
-
<
|
|
30
|
-
<
|
|
31
|
-
</
|
|
32
|
-
<
|
|
33
|
-
<
|
|
34
|
-
<
|
|
35
|
-
</
|
|
138
|
+
<nav>
|
|
139
|
+
<button>Primary</button>
|
|
140
|
+
<button class="border">Outlined</button>
|
|
141
|
+
<button class="transparent circle"><i>search</i></button>
|
|
142
|
+
</nav>
|
|
143
|
+
<article>
|
|
144
|
+
<h5>Card</h5>
|
|
145
|
+
<p>Drop md3 into a plain HTML page and write semantic markup.</p>
|
|
146
|
+
</article>
|
|
36
147
|
</main>
|
|
37
148
|
</body>
|
|
38
149
|
</html>
|
|
@@ -40,235 +151,2462 @@ Paste into any HTML file:
|
|
|
40
151
|
|
|
41
152
|
That's it. You should see an M3-styled page that picks light or dark automatically from your OS preference.
|
|
42
153
|
|
|
43
|
-
|
|
154
|
+
---
|
|
44
155
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
156
|
+
## Bootstrap
|
|
157
|
+
|
|
158
|
+
```html
|
|
159
|
+
<html data-theme="stackific" data-mode="auto">
|
|
49
160
|
```
|
|
50
161
|
|
|
51
|
-
|
|
162
|
+
| Attribute | Values | Notes |
|
|
163
|
+
| ------------ | ---------------------------- | ------------------------------------------------------ |
|
|
164
|
+
| `data-theme` | any baked theme name | Pure attribute swap; no JS required for static pages. Omit to use the default (`stackific`). |
|
|
165
|
+
| `data-mode` | `auto` \| `light` \| `dark` | `auto` follows `prefers-color-scheme` in CSS (no JS). |
|
|
166
|
+
| `data-ui` | `#some-id` | On any element, clicking delegates to `ui("#some-id")`. Anchors without `href` also respond to Enter. |
|
|
52
167
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
168
|
+
Mode is persisted to `localStorage["md3:mode"]`, theme to `localStorage["md3:theme"]`. The stored value beats the hardcoded `data-mode` / `data-theme` on `<html>`.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Runtime API
|
|
57
173
|
|
|
58
|
-
|
|
174
|
+
A single global function `ui(...)` (also `import { ui } from "@stackific/md3"`). The runtime auto-rescans the DOM via a `MutationObserver`, so calling `ui()` after injecting markup is usually optional.
|
|
175
|
+
|
|
176
|
+
| Call | Effect |
|
|
177
|
+
| ----------------------------------- | --------------------------------------------------------------- |
|
|
178
|
+
| `ui()` | Re-scan the DOM (fields, sliders, ripples, progress, triggers). |
|
|
179
|
+
| `ui("guid")` | Returns a UUIDv4 string. |
|
|
180
|
+
| `ui("mode")` | Returns current mode: `"auto"` \| `"light"` \| `"dark"`. |
|
|
181
|
+
| `ui("mode", "dark")` | Set mode. Persists to `localStorage["md3:mode"]`. |
|
|
182
|
+
| `ui("themes")` | Returns array of baked theme names. |
|
|
183
|
+
| `ui("theme", "stackific")` | Swap baked theme. Persists to `localStorage["md3:theme"]`. |
|
|
184
|
+
| `await ui("theme", "#1447E6")` | Generate theme from hex. Requires `material-dynamic-colors`. |
|
|
185
|
+
| `await ui("theme", url \| File \| Blob)` | Generate theme from image / blob. Requires `material-dynamic-colors`. |
|
|
186
|
+
| `ui("theme", { light, dark })` | Apply precomputed CSS-string per mode. |
|
|
187
|
+
| `await ui("theme")` | Returns the currently-applied `{ light, dark }` token strings. |
|
|
188
|
+
| `ui("#my-dialog")` | Toggle a `<dialog>`. |
|
|
189
|
+
| `ui("#my-menu")` | Toggle a `<menu>`. |
|
|
190
|
+
| `ui("#my-snackbar")` | Show snackbar for 6000 ms. |
|
|
191
|
+
| `ui("#my-snackbar", 3000)` | Show snackbar for N ms. |
|
|
192
|
+
| `ui("#my-snackbar", -1)` | Show until clicked. |
|
|
193
|
+
| `ui("#my-page")` | Activate a `.page` (siblings deactivate). |
|
|
194
|
+
| `ui("#anything-else")` | Toggle `.active` on the target. |
|
|
195
|
+
|
|
196
|
+
`ui("#id")` toggles: calling it on an open element closes it, calling it on a closed one opens it.
|
|
197
|
+
|
|
198
|
+
**The JS file is almost optional.** Theme/mode swapping, dialogs, menus, snackbars, overlays, pages, and tabs all work through the CSS `.active` class plus `data-ui="#id"` clicks the browser handles natively. The runtime is required only for: slider value rendering, textarea auto-resize (on browsers without `field-sizing`), the file/color/password field wiring, and `await ui("theme", …)` MDC generation.
|
|
59
199
|
|
|
60
200
|
---
|
|
61
201
|
|
|
62
|
-
##
|
|
202
|
+
## Main layout
|
|
63
203
|
|
|
64
|
-
|
|
204
|
+
Any element that contains `<main>` becomes a grid with slots for edge `<nav>`s, `<header>`, `<main>`, and `<footer>`. You don't need to use every slot.
|
|
65
205
|
|
|
66
206
|
```html
|
|
67
|
-
<
|
|
207
|
+
<nav class="left">...</nav>
|
|
208
|
+
<nav class="right">...</nav>
|
|
209
|
+
<nav class="top">...</nav>
|
|
210
|
+
<nav class="bottom">...</nav>
|
|
211
|
+
<header class="responsive | fixed">...</header>
|
|
212
|
+
<main class="responsive">...</main>
|
|
213
|
+
<footer class="responsive | fixed">...</footer>
|
|
68
214
|
```
|
|
69
215
|
|
|
70
|
-
|
|
71
|
-
|---|---|---|
|
|
72
|
-
| `data-theme` | any name listed in `$themes` | Which brand theme supplies the tokens |
|
|
73
|
-
| `data-mode` | `"auto"`, `"light"`, `"dark"` | Color mode preference |
|
|
216
|
+
Grid composition:
|
|
74
217
|
|
|
75
|
-
|
|
218
|
+
```
|
|
219
|
+
nav.left | nav.top | nav.right
|
|
220
|
+
nav.left | header | nav.right
|
|
221
|
+
nav.left | main | nav.right
|
|
222
|
+
nav.left | footer | nav.right
|
|
223
|
+
nav.left | nav.bottom | nav.right
|
|
224
|
+
```
|
|
76
225
|
|
|
77
|
-
|
|
226
|
+
`.responsive` caps content at 75 rem and centers it. `.fixed` makes header / footer sticky. For RTL languages set `dir="rtl"` on `<body>` or any ancestor.
|
|
78
227
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
228
|
+
### Compact (mobile)
|
|
229
|
+
|
|
230
|
+
```html
|
|
231
|
+
<nav class="bottom">
|
|
232
|
+
<a><i>home</i><span>Home</span></a>
|
|
233
|
+
<a><i>search</i><span>Search</span></a>
|
|
234
|
+
<a><i>share</i><span>Share</span></a>
|
|
235
|
+
</nav>
|
|
236
|
+
<main class="responsive">
|
|
237
|
+
<h3>Compact</h3>
|
|
238
|
+
</main>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Medium (tablet rail)
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<nav class="left">
|
|
245
|
+
<a><i>home</i><span>Home</span></a>
|
|
246
|
+
<a><i>search</i><span>Search</span></a>
|
|
247
|
+
<a><i>share</i><span>Share</span></a>
|
|
248
|
+
</nav>
|
|
249
|
+
<main class="responsive">
|
|
250
|
+
<h3>Medium</h3>
|
|
251
|
+
</main>
|
|
82
252
|
```
|
|
83
253
|
|
|
84
|
-
|
|
254
|
+
### Expanded (desktop drawer)
|
|
255
|
+
|
|
256
|
+
```html
|
|
257
|
+
<nav class="left max">
|
|
258
|
+
<a><i>home</i><span>Home</span></a>
|
|
259
|
+
<a><i>search</i><span>Search</span></a>
|
|
260
|
+
<a><i>share</i><span>Share</span></a>
|
|
261
|
+
</nav>
|
|
262
|
+
<main class="responsive">
|
|
263
|
+
<h3>Expanded</h3>
|
|
264
|
+
</main>
|
|
265
|
+
```
|
|
85
266
|
|
|
86
|
-
###
|
|
267
|
+
### Multi-pane
|
|
87
268
|
|
|
88
|
-
```
|
|
89
|
-
|
|
269
|
+
```html
|
|
270
|
+
<nav class="left">…</nav>
|
|
271
|
+
<main class="responsive">
|
|
272
|
+
<div class="grid">
|
|
273
|
+
<div class="s12 m6 l6"><h3>Pane 1</h3></div>
|
|
274
|
+
<div class="s12 m6 l6"><h3>Pane 2</h3></div>
|
|
275
|
+
</div>
|
|
276
|
+
</main>
|
|
90
277
|
```
|
|
91
278
|
|
|
92
|
-
###
|
|
279
|
+
### Empty state
|
|
93
280
|
|
|
94
|
-
|
|
281
|
+
```html
|
|
282
|
+
<div class="fill medium-height middle-align center-align">
|
|
283
|
+
<div class="center-align">
|
|
284
|
+
<i class="extra">mail</i>
|
|
285
|
+
<h5>You have no new messages</h5>
|
|
286
|
+
<p>Click the button to start a conversation</p>
|
|
287
|
+
<div class="space"></div>
|
|
288
|
+
<nav class="center-align">
|
|
289
|
+
<button class="round">Send a message</button>
|
|
290
|
+
</nav>
|
|
291
|
+
</div>
|
|
292
|
+
</div>
|
|
293
|
+
```
|
|
95
294
|
|
|
96
295
|
---
|
|
97
296
|
|
|
98
|
-
##
|
|
297
|
+
## Components
|
|
99
298
|
|
|
100
|
-
|
|
299
|
+
### Badge
|
|
101
300
|
|
|
102
|
-
|
|
103
|
-
/* whole site */
|
|
104
|
-
:root {
|
|
105
|
-
--primary: #ff5722;
|
|
106
|
-
--on-primary: #ffffff;
|
|
107
|
-
--primary-container: #ffe0d6;
|
|
108
|
-
}
|
|
301
|
+
Corner indicators placed inside another element. Default error-colored.
|
|
109
302
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
303
|
+
```html
|
|
304
|
+
<button class="circle">
|
|
305
|
+
<i>mail</i>
|
|
306
|
+
<div class="badge">3</div>
|
|
307
|
+
</button>
|
|
308
|
+
|
|
309
|
+
<button class="chip circle">
|
|
310
|
+
<i>mail</i>
|
|
311
|
+
<div class="badge">3</div>
|
|
312
|
+
</button>
|
|
114
313
|
```
|
|
115
314
|
|
|
116
|
-
|
|
315
|
+
| Class | Result |
|
|
316
|
+
| -------------------------------------------------------------------- | ------------------------------------- |
|
|
317
|
+
| _(none)_ | Top-right of parent, `error` colors. |
|
|
318
|
+
| `.top` / `.bottom` / `.left` / `.right` | Corner override. |
|
|
319
|
+
| `.fill` / `.primary` / `.secondary` / `.tertiary` | Role-colored background. |
|
|
320
|
+
| `.border` | Outlined on surface background. |
|
|
321
|
+
| `.circle` / `.square` / `.round` / `.no-round` / corner-round classes | Shape variants. |
|
|
322
|
+
| `.min` | Dot only (no text). |
|
|
323
|
+
| `.none` | Inline (not absolutely positioned). |
|
|
117
324
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
325
|
+
### Button
|
|
326
|
+
|
|
327
|
+
```html
|
|
328
|
+
<button>Button</button>
|
|
329
|
+
<a class="button">Link button</a>
|
|
330
|
+
|
|
331
|
+
<button>
|
|
332
|
+
<i>home</i>
|
|
333
|
+
<span>Button</span>
|
|
334
|
+
</button>
|
|
124
335
|
```
|
|
125
336
|
|
|
126
|
-
|
|
337
|
+
`<button>` and `<a class="button">` are interchangeable. Variants combine on the same element.
|
|
338
|
+
|
|
339
|
+
| Class | Result |
|
|
340
|
+
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
|
341
|
+
| _(none)_ | Filled with `primary`, 2.5 rem high, fully-rounded. |
|
|
342
|
+
| `.small` / `.large` / `.extra` | 2 / 3 / 3.5 rem high. |
|
|
343
|
+
| `.border` | Outlined; `primary-text` on transparent background. |
|
|
344
|
+
| `.fill` | `secondary-container` background. |
|
|
345
|
+
| `.primary` / `.secondary` / `.tertiary` | Role-colored background. |
|
|
346
|
+
| `.transparent` | Drops background and box-shadow; for icon buttons. |
|
|
347
|
+
| `.square` / `.circle` | No padding; equal block/inline size. |
|
|
348
|
+
| `.round` / `.no-round` / `.small-round` / `.large-round` | Corner-radius scale. |
|
|
349
|
+
| `.left-round` / `.right-round` / `.top-round` / `.bottom-round` | Per-corner radius. |
|
|
350
|
+
| `.responsive` | Fills the container's inline-size. |
|
|
351
|
+
| `.horizontal` / `.vertical` | Row vs column flow of children. |
|
|
352
|
+
| `.extend` | Collapses to icon; expands label on hover or `.active`. |
|
|
353
|
+
| `.active` | `primary-container` background. |
|
|
354
|
+
| `[disabled]` | 50% opacity, no pointer-events. |
|
|
355
|
+
|
|
356
|
+
#### Responsive button
|
|
357
|
+
|
|
358
|
+
Stretches to fill its container.
|
|
127
359
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
| Primary | `--primary`, `--on-primary`, `--primary-container`, `--on-primary-container` |
|
|
131
|
-
| Secondary | `--secondary`, `--on-secondary`, `--secondary-container`, `--on-secondary-container` |
|
|
132
|
-
| Tertiary | `--tertiary`, `--on-tertiary`, `--tertiary-container`, `--on-tertiary-container` |
|
|
133
|
-
| Error | `--error`, `--on-error`, `--error-container`, `--on-error-container` |
|
|
134
|
-
| Neutral | `--background`, `--on-background`, `--surface`, `--on-surface`, `--surface-variant`, `--on-surface-variant`, `--outline`, `--outline-variant`, `--shadow`, `--scrim` |
|
|
135
|
-
| Surface tonal | `--surface-dim`, `--surface-bright`, `--surface-container-lowest`, `--surface-container-low`, `--surface-container`, `--surface-container-high`, `--surface-container-highest` |
|
|
136
|
-
| Inverse | `--inverse-surface`, `--inverse-on-surface`, `--inverse-primary` |
|
|
137
|
-
| Structural | `--size`, `--font`, `--font-icon`, `--speed1`..`--speed4`, `--active`, `--overlay`, `--elevate1`..`--elevate3`, `--top`, `--bottom`, `--left`, `--right`, `--image` |
|
|
360
|
+
```html
|
|
361
|
+
<button class="responsive">Button</button>
|
|
138
362
|
|
|
139
|
-
|
|
363
|
+
<button class="responsive">
|
|
364
|
+
<i>home</i>
|
|
365
|
+
<span>Button</span>
|
|
366
|
+
</button>
|
|
367
|
+
```
|
|
140
368
|
|
|
141
|
-
|
|
369
|
+
#### FAB
|
|
142
370
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
371
|
+
Floating Action Button — the primary action of a screen.
|
|
372
|
+
|
|
373
|
+
```html
|
|
374
|
+
<button class="circle extra">
|
|
375
|
+
<i>add</i>
|
|
376
|
+
</button>
|
|
377
|
+
|
|
378
|
+
<button class="square extra">
|
|
379
|
+
<i>add</i>
|
|
380
|
+
</button>
|
|
381
|
+
|
|
382
|
+
<button class="circle extra left-round top-round">
|
|
383
|
+
<i>add</i>
|
|
384
|
+
</button>
|
|
151
385
|
```
|
|
152
386
|
|
|
153
|
-
|
|
387
|
+
#### Extended FAB
|
|
154
388
|
|
|
155
|
-
|
|
389
|
+
Wider FAB with a text label.
|
|
390
|
+
|
|
391
|
+
```html
|
|
392
|
+
<button class="extend circle">
|
|
393
|
+
<i>add</i>
|
|
394
|
+
<span>Create</span>
|
|
395
|
+
</button>
|
|
396
|
+
|
|
397
|
+
<button class="extend square">
|
|
398
|
+
<i>add</i>
|
|
399
|
+
<span>Create</span>
|
|
400
|
+
</button>
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
#### FAB menu
|
|
404
|
+
|
|
405
|
+
A FAB that opens a menu of related actions.
|
|
406
|
+
|
|
407
|
+
```html
|
|
408
|
+
<div>
|
|
409
|
+
<button class="circle extra">
|
|
410
|
+
<i>more_horiz</i>
|
|
411
|
+
</button>
|
|
412
|
+
<menu class="group no-wrap small-space top">
|
|
413
|
+
<li><button class="fill"><i>search</i><span>Search</span></button></li>
|
|
414
|
+
<li><button class="fill"><i>home</i><span>Home</span></button></li>
|
|
415
|
+
<li><button class="fill"><i>more_vert</i><span>About</span></button></li>
|
|
416
|
+
</menu>
|
|
417
|
+
</div>
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
#### Icon button
|
|
421
|
+
|
|
422
|
+
A transparent button shaped only on hover/press.
|
|
423
|
+
|
|
424
|
+
```html
|
|
425
|
+
<button class="transparent circle">
|
|
426
|
+
<i>search</i>
|
|
427
|
+
</button>
|
|
428
|
+
|
|
429
|
+
<button class="transparent circle">
|
|
430
|
+
<img class="responsive" src="/avatar.png">
|
|
431
|
+
</button>
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
#### Button groups
|
|
435
|
+
|
|
436
|
+
Standard groups, connected groups, and split buttons. Children should use directional corner rounds.
|
|
437
|
+
|
|
438
|
+
```html
|
|
439
|
+
<nav class="group">
|
|
440
|
+
<button class="left-round">Left</button>
|
|
441
|
+
<button class="no-round">Center</button>
|
|
442
|
+
<button class="right-round">Right</button>
|
|
443
|
+
</nav>
|
|
444
|
+
|
|
445
|
+
<nav class="group connected">
|
|
446
|
+
<button class="left-round">Left</button>
|
|
447
|
+
<button class="no-round">Center</button>
|
|
448
|
+
<button class="right-round">Right</button>
|
|
449
|
+
</nav>
|
|
450
|
+
|
|
451
|
+
<nav class="group split">
|
|
452
|
+
<button class="left-round">
|
|
453
|
+
<i>add_circle</i>
|
|
454
|
+
<span>Action</span>
|
|
455
|
+
</button>
|
|
456
|
+
<button class="right-round square">
|
|
457
|
+
<i>keyboard_arrow_down</i>
|
|
458
|
+
</button>
|
|
459
|
+
</nav>
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
Add `.secondary` / `.tertiary` on `nav.group.split` to colorize the group.
|
|
463
|
+
|
|
464
|
+
### Card
|
|
465
|
+
|
|
466
|
+
```html
|
|
467
|
+
<article>
|
|
468
|
+
<h5>Title</h5>
|
|
469
|
+
<p>Description</p>
|
|
470
|
+
<nav>
|
|
471
|
+
<button>Action</button>
|
|
472
|
+
</nav>
|
|
473
|
+
</article>
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
| Class | Result |
|
|
477
|
+
| ------------------------------------------------------------------------------------------- | ----------------------------------- |
|
|
478
|
+
| _(none)_ | Elevated, `surface-container-low`. |
|
|
479
|
+
| `.border` | No shadow, outline border. |
|
|
480
|
+
| `.fill` / `.primary-container` / `.secondary-container` / `.tertiary-container` | Role-colored background. |
|
|
481
|
+
| `.small` / `.medium` / `.large` | 12 / 20 / 32 rem block-size. |
|
|
482
|
+
| `.round` / `.no-round` / `.left-round` / `.right-round` / `.top-round` / `.bottom-round` | Corner radius. |
|
|
483
|
+
| `.padding` / `.no-padding` / `.tiny-padding` / `.small-padding` / `.medium-padding` / `.large-padding` | Inner padding override. |
|
|
484
|
+
| `.elevate` / `.no-elevate` / `.small-elevate` / `.medium-elevate` / `.large-elevate` | Shadow override. |
|
|
485
|
+
|
|
486
|
+
#### Card with leading media
|
|
487
|
+
|
|
488
|
+
```html
|
|
489
|
+
<article>
|
|
490
|
+
<div class="row">
|
|
491
|
+
<img class="circle large" src="/avatar.png">
|
|
492
|
+
<div class="max">
|
|
493
|
+
<h5>Title</h5>
|
|
494
|
+
<div>Supporting text</div>
|
|
495
|
+
</div>
|
|
496
|
+
</div>
|
|
497
|
+
<nav>
|
|
498
|
+
<button>Action</button>
|
|
499
|
+
</nav>
|
|
500
|
+
</article>
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
#### Card with hero media
|
|
504
|
+
|
|
505
|
+
```html
|
|
506
|
+
<article class="no-padding">
|
|
507
|
+
<img class="responsive medium" src="/hero.jpg">
|
|
508
|
+
<div class="row absolute bottom left right padding bottom-shadow">
|
|
509
|
+
<h5>Title</h5>
|
|
510
|
+
<div class="max"></div>
|
|
511
|
+
<button class="circle transparent"><i>more_vert</i></button>
|
|
512
|
+
</div>
|
|
513
|
+
</article>
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
#### Side-by-side card
|
|
517
|
+
|
|
518
|
+
```html
|
|
519
|
+
<article class="no-padding">
|
|
520
|
+
<div class="grid no-space">
|
|
521
|
+
<div class="s6"><img class="responsive" src="/photo.jpg"></div>
|
|
522
|
+
<div class="s6">
|
|
523
|
+
<div class="padding">
|
|
524
|
+
<h5>Title</h5>
|
|
525
|
+
<p>Description</p>
|
|
526
|
+
<nav><button class="border round">Action</button></nav>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
</article>
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Checkbox
|
|
534
|
+
|
|
535
|
+
```html
|
|
536
|
+
<label class="checkbox">
|
|
537
|
+
<input type="checkbox">
|
|
538
|
+
<span></span>
|
|
539
|
+
</label>
|
|
540
|
+
|
|
541
|
+
<label class="checkbox">
|
|
542
|
+
<input type="checkbox">
|
|
543
|
+
<span>Click here</span>
|
|
544
|
+
</label>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Sizes: `.small`, _(default)_, `.large`, `.extra`.
|
|
548
|
+
|
|
549
|
+
#### With icons
|
|
156
550
|
|
|
157
|
-
|
|
551
|
+
```html
|
|
552
|
+
<label class="checkbox icon">
|
|
553
|
+
<input type="checkbox">
|
|
554
|
+
<span>
|
|
555
|
+
<i>close</i>
|
|
556
|
+
<i>done</i>
|
|
557
|
+
</span>
|
|
558
|
+
</label>
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
#### Inside a field
|
|
562
|
+
|
|
563
|
+
```html
|
|
564
|
+
<div class="field middle-align">
|
|
565
|
+
<nav>
|
|
566
|
+
<label class="checkbox"><input type="checkbox"><span>Item 1</span></label>
|
|
567
|
+
<label class="checkbox"><input type="checkbox"><span>Item 2</span></label>
|
|
568
|
+
<label class="checkbox"><input type="checkbox"><span>Item 3</span></label>
|
|
569
|
+
</nav>
|
|
570
|
+
<output>Helper text</output>
|
|
571
|
+
</div>
|
|
572
|
+
```
|
|
158
573
|
|
|
159
|
-
|
|
574
|
+
#### Indeterminate state
|
|
575
|
+
|
|
576
|
+
Set via JavaScript — there is no HTML attribute for this:
|
|
160
577
|
|
|
161
578
|
```js
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
579
|
+
document.getElementById("my-checkbox").indeterminate = true;
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
### Chip
|
|
583
|
+
|
|
584
|
+
```html
|
|
585
|
+
<button class="chip">Chip</button>
|
|
586
|
+
|
|
587
|
+
<button class="chip">
|
|
588
|
+
<i>home</i>
|
|
589
|
+
<span>Chip</span>
|
|
590
|
+
</button>
|
|
591
|
+
|
|
592
|
+
<a class="chip">Link chip</a>
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
`<button class="chip">` and `<a class="chip">` are interchangeable.
|
|
596
|
+
|
|
597
|
+
| Class | Result |
|
|
598
|
+
| ------------------------------------------------------------------------ | ------------------------------- |
|
|
599
|
+
| _(none)_ | 2 rem, outlined. |
|
|
600
|
+
| `.small` / `.medium` / `.large` | 2 / 2.5 / 3 rem. |
|
|
601
|
+
| `.fill` | Filled (no border). |
|
|
602
|
+
| `.primary` / `.secondary` / `.tertiary` | Role-colored background. |
|
|
603
|
+
| `.border` / `.no-border` | Border control. |
|
|
604
|
+
| `.circle` / `.square` | Equal block/inline size. |
|
|
605
|
+
| `.round` / `.no-round` / corner-round classes | Corner radius. |
|
|
606
|
+
| `.horizontal` / `.vertical` | Child flow. |
|
|
607
|
+
|
|
608
|
+
Canonical chip patterns:
|
|
609
|
+
|
|
610
|
+
```html
|
|
611
|
+
<!-- Suggestion -->
|
|
612
|
+
<button class="chip">Suggestion</button>
|
|
613
|
+
|
|
614
|
+
<!-- Input (removable) -->
|
|
615
|
+
<button class="chip">
|
|
616
|
+
<span>Input</span>
|
|
617
|
+
<i>close</i>
|
|
618
|
+
</button>
|
|
619
|
+
|
|
620
|
+
<!-- Filter -->
|
|
621
|
+
<button class="chip">
|
|
622
|
+
<i>done</i>
|
|
623
|
+
<span>Filter</span>
|
|
624
|
+
</button>
|
|
625
|
+
|
|
626
|
+
<!-- Assist with leading icon -->
|
|
627
|
+
<button class="chip">
|
|
628
|
+
<i class="primary-text">today</i>
|
|
629
|
+
<span>Assist</span>
|
|
630
|
+
</button>
|
|
631
|
+
|
|
632
|
+
<!-- With image -->
|
|
633
|
+
<button class="chip">
|
|
634
|
+
<img src="/favicon.png">
|
|
635
|
+
<span>Image</span>
|
|
636
|
+
</button>
|
|
637
|
+
```
|
|
638
|
+
|
|
639
|
+
### Container
|
|
640
|
+
|
|
641
|
+
The main content of a page.
|
|
642
|
+
|
|
643
|
+
```html
|
|
644
|
+
<main class="responsive">…</main>
|
|
167
645
|
```
|
|
168
646
|
|
|
169
|
-
`
|
|
647
|
+
`.responsive` caps inline-size at 75 rem and centers; `.max` removes the cap.
|
|
648
|
+
|
|
649
|
+
### Dialog
|
|
650
|
+
|
|
651
|
+
```html
|
|
652
|
+
<dialog>
|
|
653
|
+
<h5>Title</h5>
|
|
654
|
+
<p>Content of dialog</p>
|
|
655
|
+
<nav class="right-align no-space">
|
|
656
|
+
<button class="transparent link">Cancel</button>
|
|
657
|
+
<button class="transparent link">Confirm</button>
|
|
658
|
+
</nav>
|
|
659
|
+
</dialog>
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
| Class | Result |
|
|
663
|
+
| ------------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
|
664
|
+
| _(none)_ | Centered modal, 80% max block-size. |
|
|
665
|
+
| `.small` / `.medium` / `.large` | 25% / 50% / 75%. |
|
|
666
|
+
| `.left` / `.right` | Slides in from the side, full height. With `.small` 20 rem / `.medium` 32 rem / `.large` 44 rem. |
|
|
667
|
+
| `.top` / `.bottom` | Slides in vertically, full width. With `.small` 16 rem / `.medium` 24 rem / `.large` 32 rem. |
|
|
668
|
+
| `.max` | Full-screen. |
|
|
669
|
+
| `.modal` | Opens via native `showModal()` (native backdrop, Escape, scroll lock). |
|
|
670
|
+
| `.fill` / `.primary-container` / `.secondary-container` / `.tertiary-container` | Role-colored background. |
|
|
671
|
+
| `.border` / `.round` / `.no-round` / corner-round classes | Border and corner radius. |
|
|
672
|
+
| `.padding` / `.no-padding` / `.tiny-padding` / `.small-padding` / `.medium-padding` / `.large-padding` | Padding override. |
|
|
673
|
+
| `.elevate` / `.no-elevate` / `.small-elevate` / `.medium-elevate` / `.large-elevate` | Shadow override. |
|
|
674
|
+
| `.active` | Open state (also `[open]` from native API). |
|
|
675
|
+
|
|
676
|
+
#### Opening and closing — 5 methods
|
|
677
|
+
|
|
678
|
+
**1. Add/remove `active` class**
|
|
679
|
+
|
|
680
|
+
```html
|
|
681
|
+
<dialog class="active">…</dialog>
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
**2. Native HTML `<dialog>` API**
|
|
170
685
|
|
|
171
686
|
```js
|
|
172
|
-
|
|
173
|
-
|
|
687
|
+
document.querySelector("#dialog").show(); // non-modal
|
|
688
|
+
document.querySelector("#dialog").showModal(); // modal
|
|
689
|
+
document.querySelector("#dialog").close();
|
|
174
690
|
```
|
|
175
691
|
|
|
176
|
-
|
|
692
|
+
**3. `data-ui` attribute**
|
|
693
|
+
|
|
694
|
+
```html
|
|
695
|
+
<button data-ui="#dialog">Open</button>
|
|
696
|
+
|
|
697
|
+
<dialog id="dialog">
|
|
698
|
+
<h5>Title</h5>
|
|
699
|
+
<nav class="right-align no-space">
|
|
700
|
+
<button data-ui="#dialog">Cancel</button>
|
|
701
|
+
<button data-ui="#dialog">Confirm</button>
|
|
702
|
+
</nav>
|
|
703
|
+
</dialog>
|
|
704
|
+
```
|
|
177
705
|
|
|
178
|
-
|
|
706
|
+
**4. `ui()` call**
|
|
179
707
|
|
|
180
708
|
```js
|
|
181
|
-
ui("#
|
|
182
|
-
ui("#my-snackbar"); // show snackbar for 6s
|
|
183
|
-
ui("#my-snackbar", 3000); // show for 3s
|
|
184
|
-
ui("#my-snackbar", -1); // show until clicked
|
|
185
|
-
ui("#my-page"); // activate a .page (tab-style content)
|
|
709
|
+
ui("#dialog");
|
|
186
710
|
```
|
|
187
711
|
|
|
188
|
-
|
|
712
|
+
**5. Popover API**
|
|
713
|
+
|
|
714
|
+
```html
|
|
715
|
+
<button popovertarget="dialog">Open</button>
|
|
189
716
|
|
|
190
|
-
|
|
717
|
+
<dialog id="dialog" popover>
|
|
718
|
+
<h5>Title</h5>
|
|
719
|
+
</dialog>
|
|
720
|
+
```
|
|
191
721
|
|
|
192
722
|
```js
|
|
193
|
-
|
|
194
|
-
|
|
723
|
+
document.querySelector("#dialog").showPopover();
|
|
724
|
+
document.querySelector("#dialog").hidePopover();
|
|
725
|
+
document.querySelector("#dialog").togglePopover();
|
|
195
726
|
```
|
|
196
727
|
|
|
197
|
-
|
|
728
|
+
#### Custom overlay
|
|
198
729
|
|
|
199
|
-
|
|
730
|
+
Place an `.overlay` sibling immediately before the dialog; modifier classes on the overlay are honored:
|
|
731
|
+
|
|
732
|
+
```html
|
|
733
|
+
<div class="overlay blur"></div>
|
|
734
|
+
<dialog id="dialog">…</dialog>
|
|
735
|
+
```
|
|
200
736
|
|
|
201
|
-
|
|
737
|
+
#### Navigation drawer
|
|
202
738
|
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
739
|
+
```html
|
|
740
|
+
<div class="overlay"></div>
|
|
741
|
+
<dialog id="drawer" class="left">
|
|
742
|
+
<header>
|
|
743
|
+
<nav>
|
|
744
|
+
<img class="circle large" src="/avatar.png">
|
|
745
|
+
<h6 class="max">Title</h6>
|
|
746
|
+
<button class="transparent circle large" data-ui="#drawer">
|
|
747
|
+
<i>close</i>
|
|
748
|
+
</button>
|
|
749
|
+
</nav>
|
|
750
|
+
</header>
|
|
751
|
+
<ul class="list">
|
|
752
|
+
<li class="wave round"><i>inbox</i><span class="max">Inbox</span><b>24</b></li>
|
|
753
|
+
<li class="wave round"><i>send</i><span>Outbox</span></li>
|
|
754
|
+
<li class="wave round"><i>favorite</i><span>Favorites</span></li>
|
|
755
|
+
<li class="wave round"><i>delete</i><span>Trash</span></li>
|
|
756
|
+
</ul>
|
|
757
|
+
</dialog>
|
|
209
758
|
```
|
|
210
759
|
|
|
211
|
-
###
|
|
760
|
+
### Divider
|
|
212
761
|
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
762
|
+
```html
|
|
763
|
+
<hr>
|
|
764
|
+
<hr class="small">
|
|
765
|
+
<hr class="medium">
|
|
766
|
+
<hr class="large">
|
|
767
|
+
|
|
768
|
+
<div class="divider"></div>
|
|
769
|
+
<div class="divider vertical"></div>
|
|
770
|
+
```
|
|
771
|
+
|
|
772
|
+
`.small` / `.medium` / `.large` control vertical margin (0.5 / 1 / 1.5 rem). `.vertical` produces a vertical rule.
|
|
773
|
+
|
|
774
|
+
### Expansion
|
|
775
|
+
|
|
776
|
+
Use native `<details>` / `<summary>`.
|
|
777
|
+
|
|
778
|
+
```html
|
|
779
|
+
<details>
|
|
780
|
+
<summary>Header</summary>
|
|
781
|
+
<p>Body content</p>
|
|
782
|
+
</details>
|
|
217
783
|
```
|
|
218
784
|
|
|
219
|
-
|
|
785
|
+
Multi-level:
|
|
220
786
|
|
|
221
|
-
|
|
222
|
-
|
|
787
|
+
```html
|
|
788
|
+
<details>
|
|
789
|
+
<summary>Level 1</summary>
|
|
790
|
+
<details>
|
|
791
|
+
<summary>Level 2</summary>
|
|
792
|
+
<details>
|
|
793
|
+
<summary>Level 3</summary>
|
|
794
|
+
<p>Body</p>
|
|
795
|
+
</details>
|
|
796
|
+
</details>
|
|
797
|
+
</details>
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
Custom summary (hides the marker):
|
|
801
|
+
|
|
802
|
+
```html
|
|
803
|
+
<details>
|
|
804
|
+
<summary class="none">
|
|
805
|
+
<button>Custom trigger</button>
|
|
806
|
+
</summary>
|
|
807
|
+
<p>Body</p>
|
|
808
|
+
</details>
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### Field
|
|
812
|
+
|
|
813
|
+
Wrapper for inputs, selects, textareas, and composite controls.
|
|
814
|
+
|
|
815
|
+
```html
|
|
816
|
+
<div class="field border">
|
|
817
|
+
<input type="text">
|
|
818
|
+
</div>
|
|
819
|
+
```
|
|
820
|
+
|
|
821
|
+
`.label` is optional; with it, the label floats above the input when focused or filled.
|
|
822
|
+
|
|
823
|
+
```html
|
|
824
|
+
<div class="field label border">
|
|
825
|
+
<input type="text" placeholder=" ">
|
|
826
|
+
<label>Label</label>
|
|
827
|
+
</div>
|
|
828
|
+
```
|
|
829
|
+
|
|
830
|
+
| Class | Result |
|
|
831
|
+
| ------------------------------------------- | ------------------------------------------------- |
|
|
832
|
+
| `.label` | Adds a floating label child. |
|
|
833
|
+
| `.border` | Outlined. |
|
|
834
|
+
| `.fill` | Filled (`surface-variant`). |
|
|
835
|
+
| `.round` | Pill shape. |
|
|
836
|
+
| `.small` / _(default)_ / `.large` / `.extra` | 2.5 / 3 / 3.5 / 4 rem input height. |
|
|
837
|
+
| `.prefix` | Extra start-padding for a leading icon child. |
|
|
838
|
+
| `.suffix` | Extra end-padding for a trailing icon child. |
|
|
839
|
+
| `.invalid` | Error coloring; shows `<output class="invalid">`. |
|
|
840
|
+
|
|
841
|
+
#### Input
|
|
842
|
+
|
|
843
|
+
```html
|
|
844
|
+
<div class="field border">
|
|
845
|
+
<input type="text">
|
|
846
|
+
</div>
|
|
847
|
+
|
|
848
|
+
<div class="field border">
|
|
849
|
+
<input type="text">
|
|
850
|
+
<output>Helper text</output>
|
|
851
|
+
</div>
|
|
852
|
+
|
|
853
|
+
<div class="field invalid border">
|
|
854
|
+
<input type="text">
|
|
855
|
+
<output class="invalid">Error text</output>
|
|
856
|
+
</div>
|
|
857
|
+
|
|
858
|
+
<div class="field label border">
|
|
859
|
+
<input type="text" placeholder=" ">
|
|
860
|
+
<label>Label</label>
|
|
861
|
+
</div>
|
|
862
|
+
|
|
863
|
+
<div class="field label prefix border">
|
|
864
|
+
<i>search</i>
|
|
865
|
+
<input type="text">
|
|
866
|
+
<label>Label</label>
|
|
867
|
+
</div>
|
|
868
|
+
|
|
869
|
+
<div class="field label suffix border">
|
|
870
|
+
<input type="text">
|
|
871
|
+
<label>Label</label>
|
|
872
|
+
<i>visibility</i>
|
|
873
|
+
</div>
|
|
874
|
+
|
|
875
|
+
<div class="field label prefix suffix border">
|
|
876
|
+
<i>search</i>
|
|
877
|
+
<input type="text">
|
|
878
|
+
<label>Label</label>
|
|
879
|
+
<i>tune</i>
|
|
880
|
+
</div>
|
|
881
|
+
```
|
|
882
|
+
|
|
883
|
+
Clickable prefix/suffix icons — wrap in `<a>` or use `<i class="front">`:
|
|
884
|
+
|
|
885
|
+
```html
|
|
886
|
+
<div class="field label prefix border">
|
|
887
|
+
<a><i>search</i></a>
|
|
888
|
+
<input type="text">
|
|
889
|
+
<label>Label</label>
|
|
890
|
+
</div>
|
|
891
|
+
|
|
892
|
+
<div class="field label prefix border">
|
|
893
|
+
<i class="front">search</i>
|
|
894
|
+
<input type="text">
|
|
895
|
+
<label>Label</label>
|
|
896
|
+
</div>
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
Floating-label triggers — either add `placeholder=" "` (pure CSS) or let the runtime toggle `.active`:
|
|
900
|
+
|
|
901
|
+
```html
|
|
902
|
+
<!-- CSS-only -->
|
|
903
|
+
<div class="field label border">
|
|
904
|
+
<input type="text" placeholder=" ">
|
|
905
|
+
<label>Label</label>
|
|
906
|
+
</div>
|
|
907
|
+
|
|
908
|
+
<!-- Manual control -->
|
|
909
|
+
<div class="field label border">
|
|
910
|
+
<input type="text" class="active">
|
|
911
|
+
<label class="active">Label</label>
|
|
912
|
+
</div>
|
|
913
|
+
```
|
|
914
|
+
|
|
915
|
+
Password fields auto-wire a visibility toggle when a child `<i>visibility</i>` is present:
|
|
916
|
+
|
|
917
|
+
```html
|
|
918
|
+
<div class="field label suffix border">
|
|
919
|
+
<input type="password">
|
|
920
|
+
<label>Password</label>
|
|
921
|
+
<i>visibility</i>
|
|
922
|
+
</div>
|
|
923
|
+
```
|
|
223
924
|
|
|
224
|
-
|
|
925
|
+
#### Select
|
|
225
926
|
|
|
226
|
-
|
|
927
|
+
```html
|
|
928
|
+
<div class="field suffix border">
|
|
929
|
+
<select>
|
|
930
|
+
<option>Item 1</option>
|
|
931
|
+
<option>Item 2</option>
|
|
932
|
+
<option>Item 3</option>
|
|
933
|
+
</select>
|
|
934
|
+
<i>arrow_drop_down</i>
|
|
935
|
+
</div>
|
|
936
|
+
|
|
937
|
+
<div class="field label suffix border">
|
|
938
|
+
<select>
|
|
939
|
+
<option>Item 1</option>
|
|
940
|
+
<option>Item 2</option>
|
|
941
|
+
</select>
|
|
942
|
+
<label>Label</label>
|
|
943
|
+
<i>arrow_drop_down</i>
|
|
944
|
+
<output>Helper text</output>
|
|
945
|
+
</div>
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
#### Textarea
|
|
949
|
+
|
|
950
|
+
Auto-resizes unless `[rows]` is set.
|
|
951
|
+
|
|
952
|
+
```html
|
|
953
|
+
<div class="field border">
|
|
954
|
+
<textarea></textarea>
|
|
955
|
+
</div>
|
|
956
|
+
|
|
957
|
+
<div class="field border">
|
|
958
|
+
<textarea rows="10"></textarea>
|
|
959
|
+
</div>
|
|
960
|
+
|
|
961
|
+
<div class="field label border">
|
|
962
|
+
<textarea placeholder=" "></textarea>
|
|
963
|
+
<label>Label</label>
|
|
964
|
+
</div>
|
|
965
|
+
```
|
|
966
|
+
|
|
967
|
+
#### Search
|
|
968
|
+
|
|
969
|
+
Search field with auto-suggestion menu.
|
|
970
|
+
|
|
971
|
+
```html
|
|
972
|
+
<div class="field large prefix round fill">
|
|
973
|
+
<i class="front">search</i>
|
|
974
|
+
<input>
|
|
975
|
+
<menu class="min">
|
|
976
|
+
<li class="transparent">
|
|
977
|
+
<div class="field large prefix">
|
|
978
|
+
<i class="front">arrow_back</i>
|
|
979
|
+
<input>
|
|
980
|
+
</div>
|
|
981
|
+
</li>
|
|
982
|
+
<li><i>history</i><div>Recent 1</div></li>
|
|
983
|
+
<li><i>history</i><div>Recent 2</div></li>
|
|
984
|
+
<li><i>history</i><div>Recent 3</div></li>
|
|
985
|
+
</menu>
|
|
986
|
+
</div>
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
FAB-anchored search:
|
|
990
|
+
|
|
991
|
+
```html
|
|
992
|
+
<div>
|
|
993
|
+
<button class="extra circle fill">
|
|
994
|
+
<i>search</i>
|
|
995
|
+
</button>
|
|
996
|
+
<menu class="no-wrap left min">
|
|
997
|
+
<li class="transparent">
|
|
998
|
+
<div class="field large prefix">
|
|
999
|
+
<i class="front">arrow_back</i>
|
|
1000
|
+
<input>
|
|
1001
|
+
</div>
|
|
1002
|
+
</li>
|
|
1003
|
+
<li><i>history</i><div>Recent 1</div></li>
|
|
1004
|
+
</menu>
|
|
1005
|
+
</div>
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
#### Custom inputs (file, color, date, time)
|
|
1009
|
+
|
|
1010
|
+
Wrap a hidden input in a button trigger; the runtime mirrors values back into a sibling text input.
|
|
1011
|
+
|
|
1012
|
+
```html
|
|
1013
|
+
<div>
|
|
1014
|
+
<button class="circle"><i>attach_file</i></button>
|
|
1015
|
+
<input type="file">
|
|
1016
|
+
</div>
|
|
1017
|
+
|
|
1018
|
+
<div>
|
|
1019
|
+
<button class="circle"><i>palette</i></button>
|
|
1020
|
+
<input type="color">
|
|
1021
|
+
</div>
|
|
1022
|
+
|
|
1023
|
+
<div>
|
|
1024
|
+
<button class="circle"><i>today</i></button>
|
|
1025
|
+
<input type="date">
|
|
1026
|
+
</div>
|
|
1027
|
+
|
|
1028
|
+
<div>
|
|
1029
|
+
<button class="circle"><i>schedule</i></button>
|
|
1030
|
+
<input type="time">
|
|
1031
|
+
</div>
|
|
1032
|
+
|
|
1033
|
+
<!-- With label -->
|
|
1034
|
+
<div>
|
|
1035
|
+
<button><i>attach_file</i><span>File</span></button>
|
|
1036
|
+
<input type="file">
|
|
1037
|
+
</div>
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
### Grid
|
|
227
1041
|
|
|
228
|
-
|
|
1042
|
+
12-column grid with 1 rem gap. Cell wrappers live immediately inside `.grid` — don't put `.grid` and `.s1`–`.s12` on the same element.
|
|
229
1043
|
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
"
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
1044
|
+
```html
|
|
1045
|
+
<div class="grid">
|
|
1046
|
+
<div class="s12 m6 l3"><h5>First</h5></div>
|
|
1047
|
+
<div class="s12 m6 l3"><h5>Second</h5></div>
|
|
1048
|
+
<div class="s12 m6 l3"><h5>Third</h5></div>
|
|
1049
|
+
<div class="s12 m6 l3"><h5>Fourth</h5></div>
|
|
1050
|
+
</div>
|
|
237
1051
|
```
|
|
238
1052
|
|
|
239
|
-
|
|
1053
|
+
| Class | Active |
|
|
1054
|
+
| ---------------- | ------------------ |
|
|
1055
|
+
| `.s1` … `.s12` | Always. |
|
|
1056
|
+
| `.m1` … `.m12` | ≥ 601 px. |
|
|
1057
|
+
| `.l1` … `.l12` | ≥ 993 px. |
|
|
240
1058
|
|
|
241
|
-
|
|
1059
|
+
Gap modifiers on `.grid`: `.no-space`, `.space`, `.small-space`, `.medium-space` (1.5 rem), `.large-space` (2 rem).
|
|
242
1060
|
|
|
243
|
-
|
|
1061
|
+
✅ **Do** put component elements inside the cell:
|
|
244
1062
|
|
|
245
|
-
```
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
1063
|
+
```html
|
|
1064
|
+
<div class="grid">
|
|
1065
|
+
<div class="s12 m6 l3"><article>…</article></div>
|
|
1066
|
+
<div class="s12 m6 l3"><div class="field">…</div></div>
|
|
1067
|
+
</div>
|
|
250
1068
|
```
|
|
251
1069
|
|
|
252
|
-
|
|
1070
|
+
🚫 **Don't** put grid classes directly on the element:
|
|
253
1071
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
| `src/styles/elements/_*.scss` | Per-component scales (`$-button-sizes`, `$-chip-sizes`, etc.) |
|
|
260
|
-
| `src/styles/elements/_shapes.scss` | `$-shapes` list of SVG-backed shape utilities |
|
|
1072
|
+
```html
|
|
1073
|
+
<div class="grid">
|
|
1074
|
+
<article class="s12 m6 l3">…</article> <!-- breaks layout -->
|
|
1075
|
+
</div>
|
|
1076
|
+
```
|
|
261
1077
|
|
|
262
|
-
|
|
1078
|
+
### Header & Footer
|
|
263
1079
|
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
1080
|
+
```html
|
|
1081
|
+
<header>
|
|
1082
|
+
<nav>
|
|
1083
|
+
<button class="circle transparent"><i>arrow_back</i></button>
|
|
1084
|
+
<h5 class="max">Title</h5>
|
|
1085
|
+
<button class="circle transparent"><i>more_vert</i></button>
|
|
1086
|
+
</nav>
|
|
1087
|
+
</header>
|
|
1088
|
+
|
|
1089
|
+
<footer>
|
|
1090
|
+
<nav>
|
|
1091
|
+
<button class="circle transparent"><i>check_box</i></button>
|
|
1092
|
+
<button class="circle transparent"><i>brush</i></button>
|
|
1093
|
+
<div class="max"></div>
|
|
1094
|
+
<button class="square round extra primary"><i>add</i></button>
|
|
1095
|
+
</nav>
|
|
1096
|
+
</footer>
|
|
268
1097
|
```
|
|
269
1098
|
|
|
1099
|
+
| Class | Result |
|
|
1100
|
+
| ---------------------------------- | ------------------------------------------------------------- |
|
|
1101
|
+
| _(none)_ | 4 rem min (header), 5 rem min (footer). |
|
|
1102
|
+
| `.fixed` | Sticky inside the container. |
|
|
1103
|
+
| `.responsive` | Caps content at 75 rem and centers it. |
|
|
1104
|
+
| `.max` | Removes the 75 rem cap. |
|
|
1105
|
+
|
|
1106
|
+
When `.fixed` and a scrollable parent are used together, header/footer stick to the parent's top/bottom edge:
|
|
1107
|
+
|
|
1108
|
+
```html
|
|
1109
|
+
<article class="small-width small-height scroll">
|
|
1110
|
+
<header class="fixed bold">Fixed header</header>
|
|
1111
|
+
<p>Long body content…</p>
|
|
1112
|
+
<p>…that scrolls underneath.</p>
|
|
1113
|
+
<footer class="fixed bold">Fixed footer</footer>
|
|
1114
|
+
</article>
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
### Icon
|
|
1118
|
+
|
|
1119
|
+
Material Symbols ligature. Four font variants ship inside the CSS bundle.
|
|
1120
|
+
|
|
1121
|
+
```html
|
|
1122
|
+
<i>home</i>
|
|
1123
|
+
|
|
1124
|
+
<i>
|
|
1125
|
+
<svg viewBox="0 0 24 24">
|
|
1126
|
+
<path d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z"></path>
|
|
1127
|
+
</svg>
|
|
1128
|
+
</i>
|
|
1129
|
+
|
|
1130
|
+
<i>
|
|
1131
|
+
<img src="/icon.png">
|
|
1132
|
+
</i>
|
|
1133
|
+
```
|
|
1134
|
+
|
|
1135
|
+
| Class | Size |
|
|
1136
|
+
| -------- | -------- |
|
|
1137
|
+
| `.tiny` | 1 rem |
|
|
1138
|
+
| `.small` | 1.25 rem |
|
|
1139
|
+
| _(none)_ | 1.5 rem |
|
|
1140
|
+
| `.large` | 1.75 rem |
|
|
1141
|
+
| `.extra` | 2 rem |
|
|
1142
|
+
| `.fill` | Filled (`FILL=1`) variation. Also auto-applied inside `<a class="active">` / `<button class="active">`. |
|
|
1143
|
+
|
|
1144
|
+
Switch font variant via `--font-icon`:
|
|
1145
|
+
|
|
1146
|
+
```css
|
|
1147
|
+
:root { --font-icon: "Material Symbols Rounded"; }
|
|
1148
|
+
/* "Material Symbols Outlined" (default), "Material Symbols Rounded",
|
|
1149
|
+
"Material Symbols Sharp", "Material Symbols Subset" (smaller bundle), or none */
|
|
1150
|
+
```
|
|
1151
|
+
|
|
1152
|
+
Sharing one SVG sprite across multiple icons:
|
|
1153
|
+
|
|
1154
|
+
```html
|
|
1155
|
+
<svg viewBox="0 0 24 24" style="display: none">
|
|
1156
|
+
<g id="home"><path d="M10,20V14H14V20H19V12H22L12,3L2,12H5V20H10Z"/></g>
|
|
1157
|
+
<g id="star"><path d="M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z"/></g>
|
|
1158
|
+
</svg>
|
|
1159
|
+
|
|
1160
|
+
<i><svg viewBox="0 0 24 24"><use href="#home"/></svg></i>
|
|
1161
|
+
<i><svg viewBox="0 0 24 24"><use href="#star"/></svg></i>
|
|
1162
|
+
```
|
|
1163
|
+
|
|
1164
|
+
Third-party icon fonts work too (Font Awesome, MDI, …) — load them yourself:
|
|
1165
|
+
|
|
1166
|
+
```html
|
|
1167
|
+
<i class="fa-regular fa-clock"></i>
|
|
1168
|
+
<i class="mdi mdi-clock-outline"></i>
|
|
1169
|
+
```
|
|
1170
|
+
|
|
1171
|
+
### Layout
|
|
1172
|
+
|
|
1173
|
+
Positioning containers — absolute (relative to parent) or fixed (relative to viewport).
|
|
1174
|
+
|
|
1175
|
+
```html
|
|
1176
|
+
<article class="small">
|
|
1177
|
+
<div class="absolute left bottom right">
|
|
1178
|
+
<h5>Pinned to container bottom</h5>
|
|
1179
|
+
</div>
|
|
1180
|
+
</article>
|
|
1181
|
+
|
|
1182
|
+
<div class="fixed left bottom right">
|
|
1183
|
+
<h5>Pinned to viewport bottom</h5>
|
|
1184
|
+
</div>
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
| Class | Effect |
|
|
1188
|
+
| -------------------------------------------------------------- | ----------------------------------------------- |
|
|
1189
|
+
| `.absolute` / `.fixed` | Positioning context. |
|
|
1190
|
+
| `.left` / `.right` / `.top` / `.bottom` | Pin to that edge. |
|
|
1191
|
+
| `.front` / `.back` | z-index +10 / −10. |
|
|
1192
|
+
| `.center` / `.middle` | Horizontal / vertical centering. |
|
|
1193
|
+
| `.small` / `.medium` / `.large` | With `.left.right`: 20 / 28 / 44 rem block-size. With `.top.bottom`: same inline-size. |
|
|
1194
|
+
|
|
1195
|
+
```html
|
|
1196
|
+
<article class="small">
|
|
1197
|
+
<span class="absolute center middle">Centered</span>
|
|
1198
|
+
</article>
|
|
1199
|
+
|
|
1200
|
+
<article class="small center-align middle-align">
|
|
1201
|
+
<span>Centered via alignment</span>
|
|
1202
|
+
</article>
|
|
1203
|
+
```
|
|
1204
|
+
|
|
1205
|
+
### List
|
|
1206
|
+
|
|
1207
|
+
```html
|
|
1208
|
+
<ul class="list">
|
|
1209
|
+
<li>Item</li>
|
|
1210
|
+
<li>Item</li>
|
|
1211
|
+
</ul>
|
|
1212
|
+
|
|
1213
|
+
<ol class="list">
|
|
1214
|
+
<li>Item</li>
|
|
1215
|
+
</ol>
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
| Class | Result |
|
|
1219
|
+
| --------------------------------------------------------- | ---------------------------- |
|
|
1220
|
+
| _(none)_ | 3.5 rem rows, no dividers. |
|
|
1221
|
+
| `.border` | Bottom divider between rows. |
|
|
1222
|
+
| `.no-space` / `.space` / `.small-space` | 2.5 / 3 / 3.5 rem rows. |
|
|
1223
|
+
| `.medium-space` / `.large-space` | 4.5 / 5.5 rem rows. |
|
|
1224
|
+
|
|
1225
|
+
#### Nested
|
|
1226
|
+
|
|
1227
|
+
```html
|
|
1228
|
+
<ul class="list">
|
|
1229
|
+
<li>Item</li>
|
|
1230
|
+
<li>
|
|
1231
|
+
<ul class="list">
|
|
1232
|
+
<li>Nested</li>
|
|
1233
|
+
<li>Nested</li>
|
|
1234
|
+
</ul>
|
|
1235
|
+
</li>
|
|
1236
|
+
</ul>
|
|
1237
|
+
```
|
|
1238
|
+
|
|
1239
|
+
#### Expansion list
|
|
1240
|
+
|
|
1241
|
+
```html
|
|
1242
|
+
<ul class="list">
|
|
1243
|
+
<li>Item</li>
|
|
1244
|
+
<li>
|
|
1245
|
+
<details>
|
|
1246
|
+
<summary>Header</summary>
|
|
1247
|
+
<ul class="list">
|
|
1248
|
+
<li>Inner</li>
|
|
1249
|
+
</ul>
|
|
1250
|
+
</details>
|
|
1251
|
+
</li>
|
|
1252
|
+
</ul>
|
|
1253
|
+
```
|
|
1254
|
+
|
|
1255
|
+
#### Headline and supporting text
|
|
1256
|
+
|
|
1257
|
+
```html
|
|
1258
|
+
<ul class="list border">
|
|
1259
|
+
<li>
|
|
1260
|
+
<button class="circle">A</button>
|
|
1261
|
+
<div class="max">
|
|
1262
|
+
<h6 class="small">Headline</h6>
|
|
1263
|
+
<div>Supporting text</div>
|
|
1264
|
+
</div>
|
|
1265
|
+
<label>+15 min</label>
|
|
1266
|
+
</li>
|
|
1267
|
+
</ul>
|
|
1268
|
+
```
|
|
1269
|
+
|
|
1270
|
+
With leading icon or avatar:
|
|
1271
|
+
|
|
1272
|
+
```html
|
|
1273
|
+
<ul class="list">
|
|
1274
|
+
<li>
|
|
1275
|
+
<i>home</i>
|
|
1276
|
+
<div class="max">
|
|
1277
|
+
<h6 class="small">Headline</h6>
|
|
1278
|
+
<div>Supporting text</div>
|
|
1279
|
+
</div>
|
|
1280
|
+
<label>+15 min</label>
|
|
1281
|
+
</li>
|
|
1282
|
+
<li>
|
|
1283
|
+
<img class="round" src="/avatar.png">
|
|
1284
|
+
<div class="max">
|
|
1285
|
+
<h6 class="small">Headline</h6>
|
|
1286
|
+
<div>Supporting text</div>
|
|
1287
|
+
</div>
|
|
1288
|
+
</li>
|
|
1289
|
+
</ul>
|
|
1290
|
+
```
|
|
1291
|
+
|
|
1292
|
+
### Media
|
|
1293
|
+
|
|
1294
|
+
```html
|
|
1295
|
+
<img src="/image.png" class="circle extra">
|
|
1296
|
+
|
|
1297
|
+
<video class="circle extra">
|
|
1298
|
+
<source src="/video.mp4" type="video/mp4">
|
|
1299
|
+
</video>
|
|
1300
|
+
|
|
1301
|
+
<svg class="circle extra" viewBox="0 0 24 24">
|
|
1302
|
+
<path d="…"/>
|
|
1303
|
+
</svg>
|
|
1304
|
+
```
|
|
1305
|
+
|
|
1306
|
+
| Class | Result |
|
|
1307
|
+
| ------------------------------------------------------------------ | --------------------------------------------------- |
|
|
1308
|
+
| `.tiny` / `.small` / _(default)_ / `.large` / `.extra` | 2 / 2.5 / 3 / 3.5 / 4 rem square. |
|
|
1309
|
+
| `.circle` / `.round` / `.square` | Border-radius style. |
|
|
1310
|
+
| `.no-round` / `.left-round` / `.right-round` / `.top-round` / `.bottom-round` | Per-corner radius. |
|
|
1311
|
+
| `.responsive` | 100% inline-size. |
|
|
1312
|
+
| `.responsive.tiny` / `.small` / `.medium` / `.large` / `.extra` | Fixed block-size 4 / 8 / 12 / 16 / 20 rem. |
|
|
1313
|
+
| `.empty-state` | Max 24 rem wide; for empty-state illustrations. |
|
|
1314
|
+
|
|
1315
|
+
### Menu
|
|
1316
|
+
|
|
1317
|
+
```html
|
|
1318
|
+
<div>
|
|
1319
|
+
<button>
|
|
1320
|
+
<span>Menu</span>
|
|
1321
|
+
<i>arrow_drop_down</i>
|
|
1322
|
+
</button>
|
|
1323
|
+
<menu>
|
|
1324
|
+
<li>Item 1</li>
|
|
1325
|
+
<li>Item 2</li>
|
|
1326
|
+
<li>Item 3</li>
|
|
1327
|
+
</menu>
|
|
1328
|
+
</div>
|
|
1329
|
+
```
|
|
1330
|
+
|
|
1331
|
+
With links:
|
|
1332
|
+
|
|
1333
|
+
```html
|
|
1334
|
+
<div>
|
|
1335
|
+
<button>
|
|
1336
|
+
<span>Links</span>
|
|
1337
|
+
<i>arrow_drop_down</i>
|
|
1338
|
+
</button>
|
|
1339
|
+
<menu>
|
|
1340
|
+
<li><a href="#">Item 1</a></li>
|
|
1341
|
+
<li><a href="#">Item 2</a></li>
|
|
1342
|
+
</menu>
|
|
1343
|
+
</div>
|
|
1344
|
+
```
|
|
1345
|
+
|
|
1346
|
+
With divider:
|
|
1347
|
+
|
|
1348
|
+
```html
|
|
1349
|
+
<menu>
|
|
1350
|
+
<li>Item 1</li>
|
|
1351
|
+
<li><hr></li>
|
|
1352
|
+
<li>Item 2</li>
|
|
1353
|
+
</menu>
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
Selected state:
|
|
1357
|
+
|
|
1358
|
+
```html
|
|
1359
|
+
<menu>
|
|
1360
|
+
<li>Item 1</li>
|
|
1361
|
+
<li class="active">Item 2</li>
|
|
1362
|
+
<li>Item 3</li>
|
|
1363
|
+
</menu>
|
|
1364
|
+
```
|
|
1365
|
+
|
|
1366
|
+
| Class | Result |
|
|
1367
|
+
| --------------------------------------------------------------------------------------- | ----------------------------------------------- |
|
|
1368
|
+
| _(none)_ | Anchored below trigger, full width. |
|
|
1369
|
+
| `.no-wrap` | Width fits content; never wraps. |
|
|
1370
|
+
| `.wrap` | Allow item wrap. |
|
|
1371
|
+
| `.min` | Compact anchored popover. |
|
|
1372
|
+
| `.max` | Full-screen. |
|
|
1373
|
+
| `.top` / `.bottom` / `.left` / `.right` | Open direction / alignment. |
|
|
1374
|
+
| `.border` | Outlined. |
|
|
1375
|
+
| `.group` | Visually merges with parent (no shadow / bg). |
|
|
1376
|
+
| `.no-space` / `.space` / `.tiny-space` / `.small-space` / `.medium-space` / `.large-space` / `.extra-space` | Gap scale. |
|
|
1377
|
+
|
|
1378
|
+
#### Submenu
|
|
1379
|
+
|
|
1380
|
+
```html
|
|
1381
|
+
<div>
|
|
1382
|
+
<button>
|
|
1383
|
+
<span>Menu</span>
|
|
1384
|
+
<i>arrow_drop_down</i>
|
|
1385
|
+
</button>
|
|
1386
|
+
<menu>
|
|
1387
|
+
<li>
|
|
1388
|
+
<span>Submenu</span>
|
|
1389
|
+
<menu>
|
|
1390
|
+
<li>Item</li>
|
|
1391
|
+
<li>Item</li>
|
|
1392
|
+
</menu>
|
|
1393
|
+
</li>
|
|
1394
|
+
</menu>
|
|
1395
|
+
</div>
|
|
1396
|
+
```
|
|
1397
|
+
|
|
1398
|
+
#### Grouped menu
|
|
1399
|
+
|
|
1400
|
+
`.group` makes the menu transparent and stacks groups visually.
|
|
1401
|
+
|
|
1402
|
+
```html
|
|
1403
|
+
<div>
|
|
1404
|
+
<button>
|
|
1405
|
+
<span>Grouped</span>
|
|
1406
|
+
<i>arrow_drop_down</i>
|
|
1407
|
+
</button>
|
|
1408
|
+
<menu class="group">
|
|
1409
|
+
<li>
|
|
1410
|
+
<menu>
|
|
1411
|
+
<li>Item</li>
|
|
1412
|
+
<li>Item</li>
|
|
1413
|
+
</menu>
|
|
1414
|
+
</li>
|
|
1415
|
+
<li>
|
|
1416
|
+
<menu>
|
|
1417
|
+
<li>Item</li>
|
|
1418
|
+
<li>Item</li>
|
|
1419
|
+
</menu>
|
|
1420
|
+
</li>
|
|
1421
|
+
</menu>
|
|
1422
|
+
</div>
|
|
1423
|
+
```
|
|
1424
|
+
|
|
1425
|
+
#### Opening and closing
|
|
1426
|
+
|
|
1427
|
+
Three patterns:
|
|
1428
|
+
|
|
1429
|
+
1. **Active class:** `<menu class="active">…</menu>`
|
|
1430
|
+
2. **`data-ui` attribute:** `<div data-ui="#menu"><menu id="menu">…</menu></div>`
|
|
1431
|
+
3. **`ui()` call:** `ui("#menu")`
|
|
1432
|
+
|
|
1433
|
+
Clicking outside an open menu closes it automatically.
|
|
1434
|
+
|
|
1435
|
+
### Navigation
|
|
1436
|
+
|
|
1437
|
+
`<nav>` and `.row` are interchangeable containers — `<nav>` is semantic, `.row` is not.
|
|
1438
|
+
|
|
1439
|
+
```html
|
|
1440
|
+
<nav>
|
|
1441
|
+
<button>Button</button>
|
|
1442
|
+
<a class="chip">Chip</a>
|
|
1443
|
+
<a><img class="circle" src="/avatar.png"></a>
|
|
1444
|
+
<label class="checkbox"><input type="checkbox"></label>
|
|
1445
|
+
</nav>
|
|
1446
|
+
|
|
1447
|
+
<div class="row">
|
|
1448
|
+
<div>min</div>
|
|
1449
|
+
<div class="max">max</div>
|
|
1450
|
+
<div>min</div>
|
|
1451
|
+
</div>
|
|
1452
|
+
```
|
|
1453
|
+
|
|
1454
|
+
| Class on `<nav>` / `.row` | Result |
|
|
1455
|
+
| ----------------------------------------------------------------------------------------------- | ------------------------------------- |
|
|
1456
|
+
| `.no-space` / `.tiny-space` / `.small-space` / `.medium-space` / `.large-space` | Gap: 0 / 0.5 / 1 / 1.5 / 2 rem. |
|
|
1457
|
+
| `.left-align` / `.center-align` / `.right-align` | Justify-content (also `text-align`). |
|
|
1458
|
+
| `.top-align` / `.middle-align` / `.bottom-align` | Align-items. |
|
|
1459
|
+
| `.horizontal` / `.vertical` | Flow direction. |
|
|
1460
|
+
| `.wrap` / `.no-wrap` | Flex-wrap behavior. |
|
|
1461
|
+
| `.min` | Inline-flex; shrinks to content. |
|
|
1462
|
+
| `.max` | `flex: 1` (children with `.max` grow). |
|
|
1463
|
+
| `.border` / `.round` / `.no-round` / corner-round classes | Border and corner radius. |
|
|
1464
|
+
| `.margin` / `.no-margin` / `.tiny-margin` / `.small-margin` / `.medium-margin` / `.large-margin` | Outer margin. |
|
|
1465
|
+
| `.fill` / `.primary-container` / `.secondary-container` / `.tertiary-container` | Role-colored background. |
|
|
1466
|
+
| `.elevate` / `.no-elevate` / `.small-elevate` / `.medium-elevate` / `.large-elevate` | Shadow. |
|
|
1467
|
+
|
|
1468
|
+
#### Navigation rail (vertical edge)
|
|
1469
|
+
|
|
1470
|
+
```html
|
|
1471
|
+
<nav class="left">
|
|
1472
|
+
<a><i>home</i><div>Home</div></a>
|
|
1473
|
+
<a><i>search</i><div>Search</div></a>
|
|
1474
|
+
<a><i>more_vert</i><div>More</div></a>
|
|
1475
|
+
</nav>
|
|
1476
|
+
|
|
1477
|
+
<nav class="left max">
|
|
1478
|
+
<a><i>home</i><div>Home</div></a>
|
|
1479
|
+
<a><i>search</i><div>Search</div></a>
|
|
1480
|
+
</nav>
|
|
1481
|
+
```
|
|
1482
|
+
|
|
1483
|
+
#### Navigation bar (horizontal edge)
|
|
1484
|
+
|
|
1485
|
+
```html
|
|
1486
|
+
<nav class="bottom">
|
|
1487
|
+
<a><i>home</i><div>Home</div></a>
|
|
1488
|
+
<a><i>search</i><div>Search</div></a>
|
|
1489
|
+
<a><i>more_vert</i><div>More</div></a>
|
|
1490
|
+
</nav>
|
|
1491
|
+
|
|
1492
|
+
<nav class="top max">
|
|
1493
|
+
<a><i>home</i><div>Home</div></a>
|
|
1494
|
+
</nav>
|
|
1495
|
+
```
|
|
1496
|
+
|
|
1497
|
+
#### Tabbed nav
|
|
1498
|
+
|
|
1499
|
+
```html
|
|
1500
|
+
<nav class="tabbed">
|
|
1501
|
+
<a class="active"><i>info</i><span>Overview</span></a>
|
|
1502
|
+
<a><i>style</i><span>Specs</span></a>
|
|
1503
|
+
<a><i>design_services</i><span>Guidelines</span></a>
|
|
1504
|
+
</nav>
|
|
1505
|
+
```
|
|
1506
|
+
|
|
1507
|
+
`nav.tabbed`: default 4 rem height, `.small` 3 rem, `.large` 5 rem.
|
|
1508
|
+
|
|
1509
|
+
#### Toolbar
|
|
1510
|
+
|
|
1511
|
+
```html
|
|
1512
|
+
<nav class="toolbar">
|
|
1513
|
+
<a><i>videocam_off</i></a>
|
|
1514
|
+
<a><i>mic</i></a>
|
|
1515
|
+
<a class="active"><i>front_hand</i></a>
|
|
1516
|
+
<a><i>more_vert</i></a>
|
|
1517
|
+
</nav>
|
|
1518
|
+
```
|
|
1519
|
+
|
|
1520
|
+
`.fill` (primary-container), `.vertical`, `.max` (full width) all work on `nav.toolbar`.
|
|
1521
|
+
|
|
1522
|
+
#### Group / connected / split
|
|
1523
|
+
|
|
1524
|
+
```html
|
|
1525
|
+
<nav class="group">
|
|
1526
|
+
<button class="left-round">Left</button>
|
|
1527
|
+
<button class="no-round">Center</button>
|
|
1528
|
+
<button class="right-round">Right</button>
|
|
1529
|
+
</nav>
|
|
1530
|
+
|
|
1531
|
+
<nav class="group connected">
|
|
1532
|
+
<button class="left-round">Left</button>
|
|
1533
|
+
<button class="no-round">Center</button>
|
|
1534
|
+
<button class="right-round">Right</button>
|
|
1535
|
+
</nav>
|
|
1536
|
+
|
|
1537
|
+
<nav class="group split">
|
|
1538
|
+
<button class="left-round"><i>add_circle</i><span>Action</span></button>
|
|
1539
|
+
<button class="right-round square"><i>keyboard_arrow_down</i></button>
|
|
1540
|
+
</nav>
|
|
1541
|
+
```
|
|
1542
|
+
|
|
1543
|
+
#### List form
|
|
1544
|
+
|
|
1545
|
+
```html
|
|
1546
|
+
<nav>
|
|
1547
|
+
<ul>
|
|
1548
|
+
<li><button>Button</button></li>
|
|
1549
|
+
<li><a class="chip">Chip</a></li>
|
|
1550
|
+
</ul>
|
|
1551
|
+
</nav>
|
|
1552
|
+
```
|
|
1553
|
+
|
|
1554
|
+
### Overlay
|
|
1555
|
+
|
|
1556
|
+
Scrim that blocks the screen. Used with dialogs or as a standalone loading curtain.
|
|
1557
|
+
|
|
1558
|
+
```html
|
|
1559
|
+
<div class="overlay center-align middle-align">
|
|
1560
|
+
<progress class="circle"></progress>
|
|
1561
|
+
</div>
|
|
1562
|
+
```
|
|
1563
|
+
|
|
1564
|
+
| Class | Result |
|
|
1565
|
+
| --------------------------------------------------------------------------- | ------------------------------- |
|
|
1566
|
+
| `.active` | Shown. |
|
|
1567
|
+
| `.blur` / `.small-blur` / `.medium-blur` / `.large-blur` | Backdrop-blur effect. |
|
|
1568
|
+
| `.left-align` / `.right-align` / `.center-align` / `.top-align` / `.bottom-align` / `.middle-align` | Align inner content. |
|
|
1569
|
+
|
|
1570
|
+
Opening and closing — same three patterns:
|
|
1571
|
+
|
|
1572
|
+
1. **Active class:** `<div class="overlay active">…</div>`
|
|
1573
|
+
2. **`data-ui`:** `<button data-ui="#overlay">Show</button>` + `<div class="overlay" id="overlay">…</div>`
|
|
1574
|
+
3. **`ui()`:** `ui("#overlay")`
|
|
1575
|
+
|
|
1576
|
+
### Page
|
|
1577
|
+
|
|
1578
|
+
```html
|
|
1579
|
+
<div class="page active">
|
|
1580
|
+
<h5>Title</h5>
|
|
1581
|
+
</div>
|
|
1582
|
+
```
|
|
1583
|
+
|
|
1584
|
+
| Class | Result |
|
|
1585
|
+
| ---------------------------------------------- | ------------------------------------- |
|
|
1586
|
+
| `.active` | Visible. |
|
|
1587
|
+
| `.left` / `.right` / `.top` / `.bottom` | Entry transform direction. |
|
|
1588
|
+
|
|
1589
|
+
Activating a page — three patterns:
|
|
1590
|
+
|
|
1591
|
+
1. **Active class:** add `.active` to one, remove from siblings.
|
|
1592
|
+
2. **`data-ui`:** `<a data-ui="#page1">Open</a>` — siblings at the same level deactivate.
|
|
1593
|
+
3. **`ui()`:** `ui("#page1")`.
|
|
1594
|
+
|
|
1595
|
+
### Progress
|
|
1596
|
+
|
|
1597
|
+
```html
|
|
1598
|
+
<progress></progress> <!-- indeterminate -->
|
|
1599
|
+
<progress value="25" max="100"></progress> <!-- linear -->
|
|
1600
|
+
|
|
1601
|
+
<progress class="wavy"></progress>
|
|
1602
|
+
<progress class="wavy" value="25" max="100"></progress>
|
|
1603
|
+
|
|
1604
|
+
<progress class="circle"></progress> <!-- circular indeterminate -->
|
|
1605
|
+
<progress class="circle" value="25" max="100"></progress>
|
|
1606
|
+
|
|
1607
|
+
<progress class="circle wavy"></progress>
|
|
1608
|
+
<progress class="circle wavy" value="25" max="100"></progress>
|
|
1609
|
+
```
|
|
1610
|
+
|
|
1611
|
+
| Class | Result |
|
|
1612
|
+
| ---------------- | -------------------------------------------- |
|
|
1613
|
+
| _(none)_ | Linear, 0.25 rem thick. |
|
|
1614
|
+
| `.small` / `.medium` / `.large` | 0.25 / 0.35 / 0.45 rem thick. |
|
|
1615
|
+
| `.indeterminate` | Forces animated indeterminate state. |
|
|
1616
|
+
| `.wavy` | Wavy SVG track (linear or circle). |
|
|
1617
|
+
| `.circle` | Circular; `.small` 1.5 rem / _(default)_ 2.5 / `.large` 3.5. |
|
|
1618
|
+
| `.max` | Absolutely fills the parent (use inside `<article>`, `<button>`, …). |
|
|
1619
|
+
|
|
1620
|
+
A bare `<progress></progress>` is auto-promoted to indeterminate at boot.
|
|
1621
|
+
|
|
1622
|
+
### Radio
|
|
1623
|
+
|
|
1624
|
+
```html
|
|
1625
|
+
<label class="radio">
|
|
1626
|
+
<input type="radio">
|
|
1627
|
+
<span></span>
|
|
1628
|
+
</label>
|
|
1629
|
+
|
|
1630
|
+
<label class="radio">
|
|
1631
|
+
<input type="radio">
|
|
1632
|
+
<span>Click here</span>
|
|
1633
|
+
</label>
|
|
1634
|
+
```
|
|
1635
|
+
|
|
1636
|
+
Sizes: `.small`, _(default)_, `.large`, `.extra`.
|
|
1637
|
+
|
|
1638
|
+
#### With icons
|
|
1639
|
+
|
|
1640
|
+
```html
|
|
1641
|
+
<label class="radio icon">
|
|
1642
|
+
<input type="radio">
|
|
1643
|
+
<span>
|
|
1644
|
+
<i>close</i>
|
|
1645
|
+
<i>done</i>
|
|
1646
|
+
</span>
|
|
1647
|
+
</label>
|
|
1648
|
+
```
|
|
1649
|
+
|
|
1650
|
+
#### Group inside a field
|
|
1651
|
+
|
|
1652
|
+
```html
|
|
1653
|
+
<div class="field middle-align">
|
|
1654
|
+
<nav>
|
|
1655
|
+
<label class="radio"><input type="radio" name="g"><span>Item 1</span></label>
|
|
1656
|
+
<label class="radio"><input type="radio" name="g"><span>Item 2</span></label>
|
|
1657
|
+
<label class="radio"><input type="radio" name="g"><span>Item 3</span></label>
|
|
1658
|
+
</nav>
|
|
1659
|
+
<output>Helper text</output>
|
|
1660
|
+
</div>
|
|
1661
|
+
```
|
|
1662
|
+
|
|
1663
|
+
### Shape
|
|
1664
|
+
|
|
1665
|
+
SVG-masked decorative element. Place inside `<button>`, `<div>`, or a sized container.
|
|
1666
|
+
|
|
1667
|
+
```html
|
|
1668
|
+
<div class="shape sunny"></div>
|
|
1669
|
+
|
|
1670
|
+
<div class="shape sunny">
|
|
1671
|
+
<img class="responsive" src="/favicon.png">
|
|
1672
|
+
</div>
|
|
1673
|
+
|
|
1674
|
+
<div class="small-width small-height">
|
|
1675
|
+
<div class="shape sunny max"></div>
|
|
1676
|
+
</div>
|
|
1677
|
+
```
|
|
1678
|
+
|
|
1679
|
+
| Class | Result |
|
|
1680
|
+
| ------------------------------------------------------------------------------ | ------------------------------- |
|
|
1681
|
+
| `.tiny` / `.small` / _(default)_ / `.medium` / `.large` / `.extra` | 2.5 / 3 / 3.5 / 4.5 / 5.5 / 6.5 rem. |
|
|
1682
|
+
| `.max` | Fills the parent. |
|
|
1683
|
+
| `.space` / `.no-space` / `.tiny-space` / `.small-space` / `.medium-space` / `.large-space` / `.extra-space` | Inner mask padding. |
|
|
1684
|
+
| `.rotate` / `.slow-rotate` / `.fast-rotate` | Rotation animation (12 s / 24 s / 6 s). |
|
|
1685
|
+
|
|
1686
|
+
**Shape names** (one per class):
|
|
1687
|
+
|
|
1688
|
+
`arch`, `arrow`, `boom`, `bun`, `burst`, `circle`, `clamshell`, `diamond`, `fan`, `flower`, `gem`, `ghost-ish`, `heart`, `leaf-clover4`, `leaft-clover8`, `loading-indicator`, `oval`, `pentagon`, `pill`, `pixel-circle`, `pixel-triangle`, `puffy`, `puffy-diamond`, `semicircle`, `sided-cookie4`, `sided-cookie6`, `sided-cookie7`, `sided-cookie9`, `sided-cookie12`, `slanted`, `soft-boom`, `soft-burst`, `square`, `sunny`, `triangle`, `very-sunny`, `wavy`, `wavy-circle`.
|
|
1689
|
+
|
|
1690
|
+
Inside a button:
|
|
1691
|
+
|
|
1692
|
+
```html
|
|
1693
|
+
<button class="circle extra transparent">
|
|
1694
|
+
<span class="shape sided-cookie12 max medium-space"></span>
|
|
1695
|
+
</button>
|
|
1696
|
+
```
|
|
1697
|
+
|
|
1698
|
+
Spinner:
|
|
1699
|
+
|
|
1700
|
+
```html
|
|
1701
|
+
<div class="shape sided-cookie12 transparent rotate">
|
|
1702
|
+
<button class="responsive">
|
|
1703
|
+
<i>search</i>
|
|
1704
|
+
</button>
|
|
1705
|
+
</div>
|
|
1706
|
+
```
|
|
1707
|
+
|
|
1708
|
+
### Slider
|
|
1709
|
+
|
|
1710
|
+
Default range is 0–100.
|
|
1711
|
+
|
|
1712
|
+
```html
|
|
1713
|
+
<div class="slider">
|
|
1714
|
+
<input type="range">
|
|
1715
|
+
<span></span>
|
|
1716
|
+
</div>
|
|
1717
|
+
|
|
1718
|
+
<div class="slider">
|
|
1719
|
+
<input type="range" min="4" max="8">
|
|
1720
|
+
<span></span>
|
|
1721
|
+
</div>
|
|
1722
|
+
```
|
|
1723
|
+
|
|
1724
|
+
| Class | Track size |
|
|
1725
|
+
| ------------------------------------------------------------------ | ---------- |
|
|
1726
|
+
| `.tiny` | 1 rem |
|
|
1727
|
+
| `.small` | 1.5 rem |
|
|
1728
|
+
| `.medium` | 2.5 rem |
|
|
1729
|
+
| `.large` | 3.5 rem |
|
|
1730
|
+
| `.extra` | 6 rem |
|
|
1731
|
+
| `.vertical` | Rotates 90°. |
|
|
1732
|
+
| `.max` | Fills the parent (container slider). |
|
|
1733
|
+
|
|
1734
|
+
#### Dual thumb
|
|
1735
|
+
|
|
1736
|
+
```html
|
|
1737
|
+
<div class="slider">
|
|
1738
|
+
<input type="range" value="25">
|
|
1739
|
+
<input type="range" value="50">
|
|
1740
|
+
<span></span>
|
|
1741
|
+
</div>
|
|
1742
|
+
```
|
|
1743
|
+
|
|
1744
|
+
#### Value tooltip
|
|
1745
|
+
|
|
1746
|
+
```html
|
|
1747
|
+
<div class="slider">
|
|
1748
|
+
<input type="range">
|
|
1749
|
+
<span></span>
|
|
1750
|
+
<div class="tooltip"></div>
|
|
1751
|
+
</div>
|
|
1752
|
+
```
|
|
1753
|
+
|
|
1754
|
+
#### Inset icon
|
|
1755
|
+
|
|
1756
|
+
The icon appears only with `.medium`, `.large`, or `.extra`.
|
|
1757
|
+
|
|
1758
|
+
```html
|
|
1759
|
+
<div class="slider medium">
|
|
1760
|
+
<input type="range">
|
|
1761
|
+
<span><i>sunny</i></span>
|
|
1762
|
+
</div>
|
|
1763
|
+
```
|
|
1764
|
+
|
|
1765
|
+
#### Inside a field
|
|
1766
|
+
|
|
1767
|
+
```html
|
|
1768
|
+
<div class="field middle-align">
|
|
1769
|
+
<div class="slider">
|
|
1770
|
+
<input type="range">
|
|
1771
|
+
<span></span>
|
|
1772
|
+
</div>
|
|
1773
|
+
<output>Helper</output>
|
|
1774
|
+
</div>
|
|
1775
|
+
```
|
|
1776
|
+
|
|
1777
|
+
#### Container slider
|
|
1778
|
+
|
|
1779
|
+
```html
|
|
1780
|
+
<article>
|
|
1781
|
+
<div class="slider max">
|
|
1782
|
+
<input type="range">
|
|
1783
|
+
<span></span>
|
|
1784
|
+
</div>
|
|
1785
|
+
</article>
|
|
1786
|
+
```
|
|
1787
|
+
|
|
1788
|
+
### Snackbar
|
|
1789
|
+
|
|
1790
|
+
```html
|
|
1791
|
+
<div class="snackbar">
|
|
1792
|
+
<i>warning</i>
|
|
1793
|
+
<span>I'm a snackbar</span>
|
|
1794
|
+
</div>
|
|
1795
|
+
```
|
|
1796
|
+
|
|
1797
|
+
| Class | Result |
|
|
1798
|
+
| ----------------------------------------------------------- | --------------------------------------- |
|
|
1799
|
+
| _(none)_ | Bottom-centered; auto-hides after 6 s. |
|
|
1800
|
+
| `.top` / `.bottom` | Anchor position. |
|
|
1801
|
+
| `.error` / `.primary` / `.secondary` / `.tertiary` | Role-colored background. |
|
|
1802
|
+
| `.active` | Shown. |
|
|
1803
|
+
|
|
1804
|
+
#### With action
|
|
1805
|
+
|
|
1806
|
+
```html
|
|
1807
|
+
<div class="snackbar">
|
|
1808
|
+
<div class="max">Item moved to trash</div>
|
|
1809
|
+
<a class="inverse-primary-text">Undo</a>
|
|
1810
|
+
</div>
|
|
1811
|
+
```
|
|
1812
|
+
|
|
1813
|
+
Opening — four patterns:
|
|
1814
|
+
|
|
1815
|
+
1. **Active class:** add `.active`.
|
|
1816
|
+
2. **`data-ui`:** `<button data-ui="#snack">Show</button>`.
|
|
1817
|
+
3. **`ui()`:** `ui("#snack")` — default 6000 ms; `ui("#snack", 3000)` for a custom timeout; `ui("#snack", -1)` to keep open until click.
|
|
1818
|
+
4. **Popover API:**
|
|
1819
|
+
|
|
1820
|
+
```html
|
|
1821
|
+
<button popovertarget="snack">Show</button>
|
|
1822
|
+
<div class="snackbar" id="snack" popover>I'm a snackbar</div>
|
|
1823
|
+
```
|
|
1824
|
+
|
|
1825
|
+
```js
|
|
1826
|
+
document.querySelector("#snack").showPopover();
|
|
1827
|
+
document.querySelector("#snack").hidePopover();
|
|
1828
|
+
document.querySelector("#snack").togglePopover();
|
|
1829
|
+
```
|
|
1830
|
+
|
|
1831
|
+
Only one snackbar shows at a time — opening one dismisses any open siblings.
|
|
1832
|
+
|
|
1833
|
+
### Switch
|
|
1834
|
+
|
|
1835
|
+
```html
|
|
1836
|
+
<label class="switch">
|
|
1837
|
+
<input type="checkbox">
|
|
1838
|
+
<span></span>
|
|
1839
|
+
</label>
|
|
1840
|
+
|
|
1841
|
+
<nav>
|
|
1842
|
+
<div class="max">
|
|
1843
|
+
<h6>Title</h6>
|
|
1844
|
+
<div>Complementary text</div>
|
|
1845
|
+
</div>
|
|
1846
|
+
<label class="switch">
|
|
1847
|
+
<input type="checkbox">
|
|
1848
|
+
<span></span>
|
|
1849
|
+
</label>
|
|
1850
|
+
</nav>
|
|
1851
|
+
```
|
|
1852
|
+
|
|
1853
|
+
Sizes: `.small`, _(default)_, `.large`, `.extra`.
|
|
1854
|
+
|
|
1855
|
+
#### With icons
|
|
1856
|
+
|
|
1857
|
+
```html
|
|
1858
|
+
<label class="switch icon">
|
|
1859
|
+
<input type="checkbox">
|
|
1860
|
+
<span><i>wifi</i></span>
|
|
1861
|
+
</label>
|
|
1862
|
+
|
|
1863
|
+
<label class="switch icon">
|
|
1864
|
+
<input type="checkbox">
|
|
1865
|
+
<span>
|
|
1866
|
+
<i>close</i>
|
|
1867
|
+
<i>done</i>
|
|
1868
|
+
</span>
|
|
1869
|
+
</label>
|
|
1870
|
+
```
|
|
1871
|
+
|
|
1872
|
+
#### Inside a field
|
|
1873
|
+
|
|
1874
|
+
```html
|
|
1875
|
+
<div class="field middle-align">
|
|
1876
|
+
<nav>
|
|
1877
|
+
<div class="max">
|
|
1878
|
+
<h6>Title</h6>
|
|
1879
|
+
<div>Complementary text</div>
|
|
1880
|
+
</div>
|
|
1881
|
+
<label class="switch">
|
|
1882
|
+
<input type="checkbox">
|
|
1883
|
+
<span></span>
|
|
1884
|
+
</label>
|
|
1885
|
+
</nav>
|
|
1886
|
+
</div>
|
|
1887
|
+
```
|
|
1888
|
+
|
|
1889
|
+
### Table
|
|
1890
|
+
|
|
1891
|
+
```html
|
|
1892
|
+
<table>
|
|
1893
|
+
<thead>
|
|
1894
|
+
<tr><th>Header</th><th>Header</th></tr>
|
|
1895
|
+
</thead>
|
|
1896
|
+
<tbody>
|
|
1897
|
+
<tr><td>Cell</td><td>Cell</td></tr>
|
|
1898
|
+
<tr><td>Cell</td><td>Cell</td></tr>
|
|
1899
|
+
</tbody>
|
|
1900
|
+
<tfoot>
|
|
1901
|
+
<tr><th>Footer</th><th>Footer</th></tr>
|
|
1902
|
+
</tfoot>
|
|
1903
|
+
</table>
|
|
1904
|
+
```
|
|
1905
|
+
|
|
1906
|
+
| Class on `<table>` | Result |
|
|
1907
|
+
| ---------------------------------------------------------------------------------------- | ----------------- |
|
|
1908
|
+
| `.border` | Row dividers. |
|
|
1909
|
+
| `.stripes` | Zebra rows. |
|
|
1910
|
+
| `.no-space` / `.space` / `.small-space` / `.medium-space` / `.large-space` | Cell padding. |
|
|
1911
|
+
| `.left-align` / `.center-align` / `.right-align` | Text alignment. |
|
|
1912
|
+
|
|
1913
|
+
`<th class="fixed">`, `<thead class="fixed">`, `<tfoot class="fixed">` for sticky headers/footers inside a scrolling container. `<td class="min">` / `<th class="min">` shrinks the cell to its content.
|
|
1914
|
+
|
|
1915
|
+
#### Scroll
|
|
1916
|
+
|
|
1917
|
+
```html
|
|
1918
|
+
<div class="scroll small-height">
|
|
1919
|
+
<table>
|
|
1920
|
+
<thead class="fixed">
|
|
1921
|
+
<tr><th>Header</th><th>Header</th></tr>
|
|
1922
|
+
</thead>
|
|
1923
|
+
<tbody>
|
|
1924
|
+
<tr><td>Cell</td><td>Cell</td></tr>
|
|
1925
|
+
</tbody>
|
|
1926
|
+
</table>
|
|
1927
|
+
</div>
|
|
1928
|
+
```
|
|
1929
|
+
|
|
1930
|
+
### Tabs
|
|
1931
|
+
|
|
1932
|
+
```html
|
|
1933
|
+
<div class="tabs">
|
|
1934
|
+
<a class="active">Tab 1</a>
|
|
1935
|
+
<a>Tab 2</a>
|
|
1936
|
+
<a>Tab 3</a>
|
|
1937
|
+
</div>
|
|
1938
|
+
|
|
1939
|
+
<div class="page padding active"><h5>Tab 1</h5></div>
|
|
1940
|
+
<div class="page padding"><h5>Tab 2</h5></div>
|
|
1941
|
+
<div class="page padding"><h5>Tab 3</h5></div>
|
|
1942
|
+
```
|
|
1943
|
+
|
|
1944
|
+
| Class on `.tabs` | Result |
|
|
1945
|
+
| --------------------------------------------------------- | --------------------- |
|
|
1946
|
+
| `.small` / `.large` | 2 / 4 rem min height. |
|
|
1947
|
+
| `.min` | Shorter active underline. |
|
|
1948
|
+
| `.max` | Tabs grow to fill. |
|
|
1949
|
+
| `.left-align` / `.center-align` / `.right-align` | Justify-content. |
|
|
1950
|
+
| `.horizontal` / `.vertical` | Flow direction. |
|
|
1951
|
+
|
|
1952
|
+
Activating tabs — two patterns:
|
|
1953
|
+
|
|
1954
|
+
1. **Active class:** add `.active` to one tab `<a>` and one matching `.page`, remove from siblings.
|
|
1955
|
+
2. **`data-ui`:** `<a data-ui="#page1">Tab 1</a>` — the matching `.page` activates, siblings hide.
|
|
1956
|
+
|
|
1957
|
+
### Tooltip
|
|
1958
|
+
|
|
1959
|
+
A child of the trigger element.
|
|
1960
|
+
|
|
1961
|
+
```html
|
|
1962
|
+
<button>
|
|
1963
|
+
<span>Button</span>
|
|
1964
|
+
<span class="tooltip">I'm a tooltip</span>
|
|
1965
|
+
</button>
|
|
1966
|
+
|
|
1967
|
+
<div>
|
|
1968
|
+
<button class="chip round">Hover me</button>
|
|
1969
|
+
<div class="tooltip">I'm a tooltip</div>
|
|
1970
|
+
</div>
|
|
1971
|
+
```
|
|
1972
|
+
|
|
1973
|
+
| Class | Result |
|
|
1974
|
+
| -------------------------------------------------- | ----------------------------------- |
|
|
1975
|
+
| _(none)_ | Above the parent. |
|
|
1976
|
+
| `.left` / `.right` / `.bottom` | Position override. |
|
|
1977
|
+
| `.small` / `.medium` / `.large` | 8 / 12 / 16 rem wide, multi-line. |
|
|
1978
|
+
| `.max` | Block-level 20 rem rich tooltip. |
|
|
1979
|
+
| `.no-space` / `.medium-space` / `.large-space` | Gap from anchor: 0 / −1 / −1.5 rem. |
|
|
1980
|
+
|
|
1981
|
+
#### Rich tooltip
|
|
1982
|
+
|
|
1983
|
+
```html
|
|
1984
|
+
<div>
|
|
1985
|
+
<button class="chip round">Rich tooltip</button>
|
|
1986
|
+
<div class="tooltip max">
|
|
1987
|
+
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
|
|
1988
|
+
<nav>
|
|
1989
|
+
<button>Action</button>
|
|
1990
|
+
</nav>
|
|
1991
|
+
</div>
|
|
1992
|
+
</div>
|
|
1993
|
+
```
|
|
1994
|
+
|
|
1995
|
+
### Typography
|
|
1996
|
+
|
|
1997
|
+
```html
|
|
1998
|
+
<h1>Display</h1>
|
|
1999
|
+
<h2>Display</h2>
|
|
2000
|
+
<h3>Display</h3>
|
|
2001
|
+
<h4>Headline</h4>
|
|
2002
|
+
<h5>Headline</h5>
|
|
2003
|
+
<h6>Headline</h6>
|
|
2004
|
+
```
|
|
2005
|
+
|
|
2006
|
+
Heading size modifiers: `.small`, `.large`.
|
|
2007
|
+
|
|
2008
|
+
#### Formatting
|
|
2009
|
+
|
|
2010
|
+
```html
|
|
2011
|
+
<a class="link">link</a>
|
|
2012
|
+
<a class="inverse-link">inverse-link</a>
|
|
2013
|
+
<p class="italic">italic</p>
|
|
2014
|
+
<p class="bold">bold</p>
|
|
2015
|
+
<p class="underline">underline</p>
|
|
2016
|
+
<p class="overline">overline</p>
|
|
2017
|
+
<p class="upper">upper</p>
|
|
2018
|
+
<p class="lower">lower</p>
|
|
2019
|
+
<p class="capitalize">capitalize</p>
|
|
2020
|
+
<p class="small-text">small (0.75 rem)</p>
|
|
2021
|
+
<p class="medium-text">medium (0.875 rem)</p>
|
|
2022
|
+
<p class="large-text">large (1 rem)</p>
|
|
2023
|
+
<p class="truncate">long single-line text…</p>
|
|
2024
|
+
```
|
|
2025
|
+
|
|
2026
|
+
#### Line spacing
|
|
2027
|
+
|
|
2028
|
+
`.no-line`, `.tiny-line` (1.25 rem), `.small-line` (1.5), `.medium-line` (1.75), `.large-line` (2), `.extra-line` (2.25).
|
|
2029
|
+
|
|
2030
|
+
#### Blockquote, pre, code
|
|
2031
|
+
|
|
2032
|
+
```html
|
|
2033
|
+
<blockquote>Quoted text.</blockquote>
|
|
2034
|
+
|
|
2035
|
+
<pre>Preformatted.</pre>
|
|
2036
|
+
|
|
2037
|
+
<pre>
|
|
2038
|
+
<code>console.log("hello");</code>
|
|
2039
|
+
</pre>
|
|
2040
|
+
|
|
2041
|
+
<p>
|
|
2042
|
+
The function <code>console.log()</code> prints a log message.
|
|
2043
|
+
</p>
|
|
2044
|
+
```
|
|
2045
|
+
|
|
2046
|
+
`<pre>` and `<blockquote>` modifiers: `.border`, `.no-border`, `.scroll`.
|
|
2047
|
+
|
|
2048
|
+
---
|
|
2049
|
+
|
|
2050
|
+
## Helpers
|
|
2051
|
+
|
|
2052
|
+
### Alignments
|
|
2053
|
+
|
|
2054
|
+
```html
|
|
2055
|
+
<div class="center-align middle-align">…</div>
|
|
2056
|
+
```
|
|
2057
|
+
|
|
2058
|
+
`.left-align`, `.right-align`, `.center-align` (justify + text), `.top-align`, `.middle-align`, `.bottom-align` (align-items).
|
|
2059
|
+
|
|
2060
|
+
### Blurs
|
|
2061
|
+
|
|
2062
|
+
Backdrop-blur with a translucent background.
|
|
2063
|
+
|
|
2064
|
+
```html
|
|
2065
|
+
<header class="blur">…</header>
|
|
2066
|
+
<article class="blur">…</article>
|
|
2067
|
+
<button class="blur">Blurred</button>
|
|
2068
|
+
<button class="chip blur">Chip</button>
|
|
2069
|
+
```
|
|
2070
|
+
|
|
2071
|
+
`.blur` (1 rem), `.small-blur` (0.5), `.large-blur` (1.5). Add `.light` or `.dark` to force a light/dark surface tint.
|
|
2072
|
+
|
|
2073
|
+
### Color roles
|
|
2074
|
+
|
|
2075
|
+
The only color tokens are the M3 role-based ones. Every role yields a paired surface utility (`.<role>` paints background + on-role text), a `-text` utility, a `-border` utility, and where applicable a `-container` utility.
|
|
2076
|
+
|
|
2077
|
+
```html
|
|
2078
|
+
<div class="primary">primary surface + on-primary text</div>
|
|
2079
|
+
<div class="primary-container">primary container surface + on-primary-container text</div>
|
|
2080
|
+
<span class="primary-text">primary text only</span>
|
|
2081
|
+
<div class="primary-border border">primary border only</div>
|
|
2082
|
+
```
|
|
2083
|
+
|
|
2084
|
+
| Role group | Surface | Text | Border | Container |
|
|
2085
|
+
| -------------- | ------------------- | --------------------- | ----------------------- | ---------------------- |
|
|
2086
|
+
| **Primary** | `.primary` | `.primary-text` | `.primary-border` | `.primary-container` |
|
|
2087
|
+
| **Secondary** | `.secondary` | `.secondary-text` | `.secondary-border` | `.secondary-container` |
|
|
2088
|
+
| **Tertiary** | `.tertiary` | `.tertiary-text` | `.tertiary-border` | `.tertiary-container` |
|
|
2089
|
+
| **Error** | `.error` | `.error-text` | `.error-border` | `.error-container` |
|
|
2090
|
+
|
|
2091
|
+
**Neutral surface family** (background only — `on-surface` text is inherited):
|
|
2092
|
+
|
|
2093
|
+
`.background`, `.surface`, `.surface-variant`, `.surface-dim`, `.surface-bright`, `.surface-container-lowest`, `.surface-container-low`, `.surface-container`, `.surface-container-high`, `.surface-container-highest`, `.inverse-surface`.
|
|
2094
|
+
|
|
2095
|
+
**Inverse primary:**
|
|
2096
|
+
|
|
2097
|
+
`.inverse-primary`, `.inverse-primary-text`, `.inverse-primary-border`.
|
|
2098
|
+
|
|
2099
|
+
**Transparent (structural):**
|
|
2100
|
+
|
|
2101
|
+
`.transparent`, `.transparent-text`, `.transparent-border`.
|
|
2102
|
+
|
|
2103
|
+
### Directions
|
|
2104
|
+
|
|
2105
|
+
`.horizontal` (row flex), `.vertical` (column flex). Both work on `<a>`, `<button>`, `.chip`, `nav`, `.row`, `.tabs`.
|
|
2106
|
+
|
|
2107
|
+
### Elevations
|
|
2108
|
+
|
|
2109
|
+
`.elevate`, `.no-elevate`, `.small-elevate`, `.medium-elevate`, `.large-elevate`.
|
|
2110
|
+
|
|
2111
|
+
### Forms (helpers)
|
|
2112
|
+
|
|
2113
|
+
Shape and surface helpers.
|
|
2114
|
+
|
|
2115
|
+
| Class | Effect |
|
|
2116
|
+
| ---------------------------------------------------------------------- | --------------------------------- |
|
|
2117
|
+
| `.border` / `.no-border` | 1 px outline / no border. |
|
|
2118
|
+
| `.round` / `.no-round` / `.small-round` / `.large-round` | Border-radius scale (0.5 / 2 / 3.5 rem). |
|
|
2119
|
+
| `.left-round` / `.right-round` / `.top-round` / `.bottom-round` | Per-side radius. |
|
|
2120
|
+
| `.circle` / `.square` | Round / no border-radius equal-size shape. |
|
|
2121
|
+
| `.fill` | Filled surface (`surface-variant`). |
|
|
2122
|
+
| `.extend` | Extendable label (buttons). |
|
|
2123
|
+
|
|
2124
|
+
### Margins
|
|
2125
|
+
|
|
2126
|
+
`.margin` (1 rem default). Scale modifiers: `.no-margin`, `.auto-margin`, `.tiny-margin` (0.25), `.small-margin` (0.5), `.large-margin` (1.5). Directional: `.left-margin`, `.right-margin`, `.top-margin`, `.bottom-margin`, `.horizontal-margin`, `.vertical-margin`.
|
|
2127
|
+
|
|
2128
|
+
Combine: `<div class="margin large-margin top-margin">`.
|
|
2129
|
+
|
|
2130
|
+
### Opacities
|
|
2131
|
+
|
|
2132
|
+
`.opacity` (1), `.no-opacity` (0), `.small-opacity` (0.25), `.medium-opacity` (0.5), `.large-opacity` (0.75).
|
|
2133
|
+
|
|
2134
|
+
### Paddings
|
|
2135
|
+
|
|
2136
|
+
Identical scale and directional set as margins: `.padding`, `.no-padding`, `.tiny-padding`, `.small-padding`, `.large-padding`, `.left-padding`, `.right-padding`, `.top-padding`, `.bottom-padding`, `.horizontal-padding`, `.vertical-padding`.
|
|
2137
|
+
|
|
2138
|
+
### Positions
|
|
2139
|
+
|
|
2140
|
+
| Class | Effect |
|
|
2141
|
+
| -------------------------------------- | --------------------------------------------- |
|
|
2142
|
+
| `.left` / `.right` / `.top` / `.bottom` | Pin to the edge (inset-inline / inset-block). |
|
|
2143
|
+
| `.center` | Horizontally centered (`translateX(-50%)`). |
|
|
2144
|
+
| `.middle` | Vertically centered (`translateY(-50%)`). |
|
|
2145
|
+
| `.middle.center` | Fully centered. |
|
|
2146
|
+
| `.front` | `z-index: 10`. |
|
|
2147
|
+
| `.back` | `z-index: -10`. |
|
|
2148
|
+
|
|
2149
|
+
### Responsive
|
|
2150
|
+
|
|
2151
|
+
`.responsive` fills available inline-size. `.s` (visible < 601 px), `.m` (601 – 992 px), `.l` (≥ 993 px). Combine to span ranges (e.g. `.m.l` hides on small only).
|
|
2152
|
+
|
|
2153
|
+
### Ripples
|
|
2154
|
+
|
|
2155
|
+
Pointer-driven hover/focus tint plus speed scale.
|
|
2156
|
+
|
|
2157
|
+
```html
|
|
2158
|
+
<button class="ripple">Default</button>
|
|
2159
|
+
<button class="fast-ripple">Fast (200 ms)</button>
|
|
2160
|
+
<button class="slow-ripple">Slow (1800 ms)</button>
|
|
2161
|
+
|
|
2162
|
+
<button class="chip ripple">Chip with ripple</button>
|
|
2163
|
+
```
|
|
2164
|
+
|
|
2165
|
+
### Scrolls
|
|
2166
|
+
|
|
2167
|
+
`.scroll` (`overflow: auto`), `.no-scroll` (`overflow: hidden`).
|
|
2168
|
+
|
|
2169
|
+
### Shadows
|
|
2170
|
+
|
|
2171
|
+
Inset / directional gradient shadows. Useful behind text overlaid on media.
|
|
2172
|
+
|
|
2173
|
+
```html
|
|
2174
|
+
<header class="left-shadow">…</header>
|
|
2175
|
+
<article class="bottom-shadow">…</article>
|
|
2176
|
+
<button class="left-shadow">Button</button>
|
|
2177
|
+
<button class="chip left-shadow">Chip</button>
|
|
2178
|
+
```
|
|
2179
|
+
|
|
2180
|
+
`.shadow`, `.left-shadow`, `.right-shadow`, `.top-shadow`, `.bottom-shadow`.
|
|
2181
|
+
|
|
2182
|
+
### Sizes
|
|
2183
|
+
|
|
2184
|
+
| Class | Effect |
|
|
2185
|
+
| --------------------------------------------------------------------- | ------------------------------------- |
|
|
2186
|
+
| `.tiny` / `.small` / `.medium` / `.large` / `.extra` | Component-scoped size scale. |
|
|
2187
|
+
| `.wrap` / `.no-wrap` | Block + wrap / flex no-wrap. |
|
|
2188
|
+
| `.max` | `flex: 1` inside flex containers. |
|
|
2189
|
+
| `.small-width` / `.medium-width` / `.large-width` / `.auto-width` | 12 / 24 / 36 rem / `auto` inline-size. |
|
|
2190
|
+
| `.small-height` / `.medium-height` / `.large-height` / `.auto-height` | Same scale for block-size. |
|
|
2191
|
+
|
|
2192
|
+
### Spaces
|
|
2193
|
+
|
|
2194
|
+
Vertical spacer blocks (suppressed inside `nav`, `.row`, `.grid`, `table`, `.tooltip`, `.list`, `menu`, `.shape`).
|
|
2195
|
+
|
|
2196
|
+
| Class | Height |
|
|
2197
|
+
| --------------------------- | -------- |
|
|
2198
|
+
| `.tiny-space` | 0.5 rem |
|
|
2199
|
+
| `.space` / `.small-space` | 1 rem |
|
|
2200
|
+
| `.medium-space` | 2 rem |
|
|
2201
|
+
| `.large-space` | 3 rem |
|
|
2202
|
+
| `.extra-space` | 4 rem |
|
|
2203
|
+
|
|
2204
|
+
On `<nav>` / `.row` / `.grid` / `menu`, the same class names control gap instead of block-size.
|
|
2205
|
+
|
|
2206
|
+
### Waves
|
|
2207
|
+
|
|
2208
|
+
Material radial-gradient wave on hover / focus (auto-applied to `.button`, `button`, `.chip`, `.tabs > a`, `nav.tabbed > a`, `nav.toolbar > a`, and rail-nav items). Add `.wave` to opt arbitrary elements in; `.no-wave` to opt out.
|
|
2209
|
+
|
|
2210
|
+
```html
|
|
2211
|
+
<div class="wave padding round">Custom wave target</div>
|
|
2212
|
+
<button class="no-wave">No wave</button>
|
|
2213
|
+
```
|
|
2214
|
+
|
|
2215
|
+
### Zoom
|
|
2216
|
+
|
|
2217
|
+
CSS `zoom` scaling. `.zoom` (2×), `.tiny-zoom` (2), `.small-zoom` (3), `.medium-zoom` (4), `.large-zoom` (5), `.extra-zoom` (6).
|
|
2218
|
+
|
|
2219
|
+
---
|
|
2220
|
+
|
|
2221
|
+
## Design tokens
|
|
2222
|
+
|
|
2223
|
+
Override any CSS custom property at any scope — no rebuild required.
|
|
2224
|
+
|
|
2225
|
+
```css
|
|
2226
|
+
:root {
|
|
2227
|
+
--primary: #ff5722;
|
|
2228
|
+
--on-primary: #fff;
|
|
2229
|
+
--primary-container: #ffe0d6;
|
|
2230
|
+
--on-primary-container: #410001;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
article.alert {
|
|
2234
|
+
--surface-container-low: #fff3e0;
|
|
2235
|
+
}
|
|
2236
|
+
```
|
|
2237
|
+
|
|
2238
|
+
**Color roles** — same quartet for `secondary`, `tertiary`, `error`:
|
|
2239
|
+
|
|
2240
|
+
`--primary`, `--on-primary`, `--primary-container`, `--on-primary-container`
|
|
2241
|
+
|
|
2242
|
+
**Neutrals:** `--background`, `--on-background`, `--surface`, `--on-surface`, `--surface-variant`, `--on-surface-variant`, `--outline`, `--outline-variant`, `--shadow`, `--scrim`.
|
|
2243
|
+
|
|
2244
|
+
**Surface tonal:** `--surface-dim`, `--surface-bright`, `--surface-container-lowest`, `--surface-container-low`, `--surface-container`, `--surface-container-high`, `--surface-container-highest`.
|
|
2245
|
+
|
|
2246
|
+
**Inverse:** `--inverse-surface`, `--inverse-on-surface`, `--inverse-primary`.
|
|
2247
|
+
|
|
2248
|
+
**Structural:**
|
|
2249
|
+
|
|
2250
|
+
| Token | Default |
|
|
2251
|
+
| ---------------------------------------- | --------------------------------------------------------------- |
|
|
2252
|
+
| `--size` | `1rem` (scale all sizing) |
|
|
2253
|
+
| `--font` | `Inter, Roboto, "Helvetica Neue", "Arial Nova", "Nimbus Sans", "Noto Sans", Arial, sans-serif` |
|
|
2254
|
+
| `--font-icon` | `"Material Symbols Outlined"` |
|
|
2255
|
+
| `--speed1` … `--speed4` | `0.1s` / `0.2s` / `0.3s` / `0.4s` |
|
|
2256
|
+
| `--active` | `rgb(128 128 128 / 0.192)` (hover / pressed overlay) |
|
|
2257
|
+
| `--overlay` | `rgb(0 0 0 / 0.5)` (modal scrim) |
|
|
2258
|
+
| `--elevate1` / `--elevate2` / `--elevate3` | Shadow tiers. |
|
|
2259
|
+
| `--top`, `--bottom`, `--left`, `--right` | `env(safe-area-inset-*)` for notched devices. |
|
|
2260
|
+
|
|
2261
|
+
Switch icon variant:
|
|
2262
|
+
|
|
2263
|
+
```css
|
|
2264
|
+
:root { --font-icon: "Material Symbols Rounded"; }
|
|
2265
|
+
/* "Material Symbols Outlined" (default), "Material Symbols Rounded",
|
|
2266
|
+
"Material Symbols Sharp", "Material Symbols Subset" (smaller bundle, used by
|
|
2267
|
+
checkbox/radio/switch), or `none` to disable icons entirely. */
|
|
2268
|
+
```
|
|
2269
|
+
|
|
2270
|
+
Use a custom body font:
|
|
2271
|
+
|
|
2272
|
+
```css
|
|
2273
|
+
@import url("https://fonts.googleapis.com/css2?family=Roboto+Flex:wght@400;500;700&display=swap");
|
|
2274
|
+
:root { --font: "Roboto Flex"; }
|
|
2275
|
+
```
|
|
2276
|
+
|
|
2277
|
+
Ship a narrower Symbols subset (import only the glyphs you use) to shrink the bundle:
|
|
2278
|
+
|
|
2279
|
+
```css
|
|
2280
|
+
@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:FILL@0..1&icon_names=check,check_box,check_box_outline_blank,indeterminate_check_box,radio_button_checked&display=swap");
|
|
2281
|
+
:root { --font-icon: "Material Symbols Outlined"; }
|
|
2282
|
+
```
|
|
2283
|
+
|
|
2284
|
+
### Full token override template
|
|
2285
|
+
|
|
2286
|
+
To replace the default theme entirely, override every role token at `:root` and provide a `[data-mode="dark"]` variant:
|
|
2287
|
+
|
|
2288
|
+
```css
|
|
2289
|
+
:root,
|
|
2290
|
+
:root[data-mode="light"] {
|
|
2291
|
+
--primary: #6750a4;
|
|
2292
|
+
--on-primary: #ffffff;
|
|
2293
|
+
--primary-container: #e9ddff;
|
|
2294
|
+
--on-primary-container: #22005d;
|
|
2295
|
+
--secondary: #625b71;
|
|
2296
|
+
--on-secondary: #ffffff;
|
|
2297
|
+
--secondary-container: #e8def8;
|
|
2298
|
+
--on-secondary-container: #1e192b;
|
|
2299
|
+
--tertiary: #7e5260;
|
|
2300
|
+
--on-tertiary: #ffffff;
|
|
2301
|
+
--tertiary-container: #ffd9e3;
|
|
2302
|
+
--on-tertiary-container: #31101d;
|
|
2303
|
+
--error: #ba1a1a;
|
|
2304
|
+
--on-error: #ffffff;
|
|
2305
|
+
--error-container: #ffdad6;
|
|
2306
|
+
--on-error-container: #410002;
|
|
2307
|
+
--background: #fffbff;
|
|
2308
|
+
--on-background: #1c1b1e;
|
|
2309
|
+
--surface: #fdf8fd;
|
|
2310
|
+
--on-surface: #1c1b1e;
|
|
2311
|
+
--surface-variant: #e7e0eb;
|
|
2312
|
+
--on-surface-variant: #49454e;
|
|
2313
|
+
--outline: #7a757f;
|
|
2314
|
+
--outline-variant: #cac4cf;
|
|
2315
|
+
--shadow: #000000;
|
|
2316
|
+
--scrim: #000000;
|
|
2317
|
+
--inverse-surface: #313033;
|
|
2318
|
+
--inverse-on-surface: #f4eff4;
|
|
2319
|
+
--inverse-primary: #cfbcff;
|
|
2320
|
+
--surface-dim: #ddd8dd;
|
|
2321
|
+
--surface-bright: #fdf8fd;
|
|
2322
|
+
--surface-container-lowest: #ffffff;
|
|
2323
|
+
--surface-container-low: #f7f2f7;
|
|
2324
|
+
--surface-container: #f2ecf1;
|
|
2325
|
+
--surface-container-high: #ece7eb;
|
|
2326
|
+
--surface-container-highest: #e6e1e6;
|
|
2327
|
+
}
|
|
2328
|
+
|
|
2329
|
+
:root[data-mode="dark"] {
|
|
2330
|
+
--primary: #cfbcff;
|
|
2331
|
+
--on-primary: #381e72;
|
|
2332
|
+
--primary-container: #4f378a;
|
|
2333
|
+
--on-primary-container: #e9ddff;
|
|
2334
|
+
--secondary: #cbc2db;
|
|
2335
|
+
--on-secondary: #332d41;
|
|
2336
|
+
--secondary-container: #4a4458;
|
|
2337
|
+
--on-secondary-container: #e8def8;
|
|
2338
|
+
--tertiary: #efb8c8;
|
|
2339
|
+
--on-tertiary: #4a2532;
|
|
2340
|
+
--tertiary-container: #633b48;
|
|
2341
|
+
--on-tertiary-container: #ffd9e3;
|
|
2342
|
+
--error: #ffb4ab;
|
|
2343
|
+
--on-error: #690005;
|
|
2344
|
+
--error-container: #93000a;
|
|
2345
|
+
--on-error-container: #ffb4ab;
|
|
2346
|
+
--background: #1c1b1e;
|
|
2347
|
+
--on-background: #e6e1e6;
|
|
2348
|
+
--surface: #141316;
|
|
2349
|
+
--on-surface: #e6e1e6;
|
|
2350
|
+
--surface-variant: #49454e;
|
|
2351
|
+
--on-surface-variant: #cac4cf;
|
|
2352
|
+
--outline: #948f99;
|
|
2353
|
+
--outline-variant: #49454e;
|
|
2354
|
+
--shadow: #000000;
|
|
2355
|
+
--scrim: #000000;
|
|
2356
|
+
--inverse-surface: #e6e1e6;
|
|
2357
|
+
--inverse-on-surface: #313033;
|
|
2358
|
+
--inverse-primary: #6750a4;
|
|
2359
|
+
--surface-dim: #141316;
|
|
2360
|
+
--surface-bright: #3a383c;
|
|
2361
|
+
--surface-container-lowest: #0f0e11;
|
|
2362
|
+
--surface-container-low: #1c1b1e;
|
|
2363
|
+
--surface-container: #201f22;
|
|
2364
|
+
--surface-container-high: #2b292d;
|
|
2365
|
+
--surface-container-highest: #363438;
|
|
2366
|
+
}
|
|
2367
|
+
```
|
|
2368
|
+
|
|
2369
|
+
---
|
|
2370
|
+
|
|
2371
|
+
## Themes
|
|
2372
|
+
|
|
2373
|
+
Baked themes ship in the bundle and swap via `<html data-theme="<name>">`:
|
|
2374
|
+
|
|
2375
|
+
`stackific` _(default)_, `hello-pumpkin`, `sea-lettuce`, `olive`, `nord`, `vega-violet`, `wild-strawberry`, `heliotrope-magenta`, `voodoo-violet`, `red-orchid`, `green-brown`, `shakshuka`, `purple-honeycreeper`, `maldives`, `verditer`, `fennel`, `gold`, `burtuqali`.
|
|
2376
|
+
|
|
2377
|
+
Each theme sets the full M3 role-token set (`--primary`, `--secondary`, `--tertiary`, `--surface-*`, etc.) for both light and dark modes.
|
|
2378
|
+
|
|
2379
|
+
```html
|
|
2380
|
+
<html data-theme="nord" data-mode="dark">
|
|
2381
|
+
```
|
|
2382
|
+
|
|
2383
|
+
```js
|
|
2384
|
+
ui("theme", "vega-violet"); // swap to a baked theme
|
|
2385
|
+
await ui("theme", "#1447E6"); // generate from hex (needs material-dynamic-colors)
|
|
2386
|
+
```
|
|
2387
|
+
|
|
2388
|
+
---
|
|
2389
|
+
|
|
2390
|
+
## Theme and mode selector
|
|
2391
|
+
|
|
2392
|
+
If your page anchors the theme menu inside another element with `overflow: hidden` or `overflow: auto`, also add this so the popover can position itself:
|
|
2393
|
+
|
|
2394
|
+
```html
|
|
2395
|
+
<style>
|
|
2396
|
+
/* Positioning context for md3's <menu> popover relative to its trigger. */
|
|
2397
|
+
*:has(> menu[data-theme-picker]) {
|
|
2398
|
+
position: relative;
|
|
2399
|
+
}
|
|
2400
|
+
</style>
|
|
2401
|
+
```
|
|
2402
|
+
|
|
2403
|
+
### The two triggers (anywhere in `<body>`)
|
|
2404
|
+
|
|
2405
|
+
The theme picker is a `<button data-ui="#…">` paired with an empty `<menu data-theme-picker>` — md3 toggles the menu's `active` class when the button is clicked; the init script fills the menu with the available theme slugs. The appearance toggle is any element with `data-theme-toggle`;
|
|
2406
|
+
the init script cycles `auto → light → dark` on click and keeps the inner `<i>` in sync with the current mode.
|
|
2407
|
+
|
|
2408
|
+
```html
|
|
2409
|
+
<!-- Theme picker -->
|
|
2410
|
+
<div>
|
|
2411
|
+
<button data-ui="#theme-picker" aria-label="Pick theme">
|
|
2412
|
+
<i aria-hidden="true">style</i>
|
|
2413
|
+
</button>
|
|
2414
|
+
<menu id="theme-picker" class="no-wrap" data-theme-picker></menu>
|
|
2415
|
+
</div>
|
|
2416
|
+
|
|
2417
|
+
<!-- Appearance (auto / light / dark) -->
|
|
2418
|
+
<button
|
|
2419
|
+
data-theme-toggle
|
|
2420
|
+
aria-label="Cycle appearance (auto, light, dark)">
|
|
2421
|
+
<i aria-hidden="true">brightness_auto</i>
|
|
2422
|
+
</button>
|
|
2423
|
+
```
|
|
2424
|
+
|
|
2425
|
+
Notes:
|
|
2426
|
+
|
|
2427
|
+
- The `<menu>`'s `id` must match the trigger's `data-ui` value.
|
|
2428
|
+
- Add `top` / `left` / `right` classes to the `<menu>` to anchor the popover side (e.g. `class="no-wrap top"` if the trigger sits at the bottom of the page).
|
|
2429
|
+
- You can attach `data-theme-toggle` to multiple buttons (e.g. desktop + mobile) — the script wires all of them and keeps their icons in sync.
|
|
2430
|
+
|
|
2431
|
+
### Init script (before `</body>`)
|
|
2432
|
+
|
|
2433
|
+
Pure, no dependencies beyond md3's global `ui()`. Cycles the mode, populates the picker from `ui("themes")`, and writes selections back through `ui("mode", …)` / `ui("theme", …)`. md3 persists both choices to `localStorage` (`md3:mode`, `md3:theme`) so the page reopens in the same state.
|
|
2434
|
+
|
|
2435
|
+
```html
|
|
2436
|
+
<script type="module">
|
|
2437
|
+
const MODE_CYCLE = ["auto", "light", "dark"];
|
|
2438
|
+
|
|
2439
|
+
const modeIcon = (pref) =>
|
|
2440
|
+
pref === "light" ? "light_mode"
|
|
2441
|
+
: pref === "dark" ? "dark_mode"
|
|
2442
|
+
: "brightness_auto";
|
|
2443
|
+
|
|
2444
|
+
function currentMode() {
|
|
2445
|
+
const v = window.ui("mode");
|
|
2446
|
+
return v === "light" || v === "dark" || v === "auto" ? v : "auto";
|
|
2447
|
+
}
|
|
2448
|
+
|
|
2449
|
+
function syncIcons() {
|
|
2450
|
+
const icon = modeIcon(currentMode());
|
|
2451
|
+
for (const el of document.querySelectorAll("[data-theme-toggle] i")) {
|
|
2452
|
+
el.textContent = icon;
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
|
|
2456
|
+
function cycleMode() {
|
|
2457
|
+
const current = currentMode();
|
|
2458
|
+
const next =
|
|
2459
|
+
MODE_CYCLE[(MODE_CYCLE.indexOf(current) + 1) % MODE_CYCLE.length];
|
|
2460
|
+
window.ui("mode", next);
|
|
2461
|
+
syncIcons();
|
|
2462
|
+
}
|
|
2463
|
+
|
|
2464
|
+
const unslugify = (slug) =>
|
|
2465
|
+
slug
|
|
2466
|
+
.split("-")
|
|
2467
|
+
.map((w) => (w ? w[0].toUpperCase() + w.slice(1) : w))
|
|
2468
|
+
.join(" ");
|
|
2469
|
+
|
|
2470
|
+
function fillThemePickers() {
|
|
2471
|
+
const themes = (window.ui("themes") ?? []).slice().sort();
|
|
2472
|
+
for (const menu of document.querySelectorAll("[data-theme-picker]")) {
|
|
2473
|
+
menu.replaceChildren();
|
|
2474
|
+
for (const slug of themes) {
|
|
2475
|
+
const li = document.createElement("li");
|
|
2476
|
+
li.className = "wave round";
|
|
2477
|
+
li.textContent = unslugify(slug);
|
|
2478
|
+
li.dataset.themeSlug = slug;
|
|
2479
|
+
li.addEventListener("click", (e) => {
|
|
2480
|
+
window.ui("theme", slug);
|
|
2481
|
+
e.currentTarget.closest("menu")?.classList.remove("active");
|
|
2482
|
+
});
|
|
2483
|
+
menu.appendChild(li);
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
|
|
2488
|
+
function start() {
|
|
2489
|
+
for (const btn of document.querySelectorAll("[data-theme-toggle]")) {
|
|
2490
|
+
btn.addEventListener("click", cycleMode);
|
|
2491
|
+
}
|
|
2492
|
+
syncIcons();
|
|
2493
|
+
fillThemePickers();
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
// md3.js loads as a module — wait until window.ui is registered.
|
|
2497
|
+
function whenUiReady(fn) {
|
|
2498
|
+
if (typeof window.ui === "function") return fn();
|
|
2499
|
+
const id = setInterval(() => {
|
|
2500
|
+
if (typeof window.ui === "function") {
|
|
2501
|
+
clearInterval(id);
|
|
2502
|
+
fn();
|
|
2503
|
+
}
|
|
2504
|
+
}, 50);
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
if (document.readyState === "loading") {
|
|
2508
|
+
document.addEventListener("DOMContentLoaded", () => whenUiReady(start));
|
|
2509
|
+
} else {
|
|
2510
|
+
whenUiReady(start);
|
|
2511
|
+
}
|
|
2512
|
+
</script>
|
|
2513
|
+
```
|
|
2514
|
+
|
|
2515
|
+
---
|
|
2516
|
+
|
|
2517
|
+
## Breakpoints
|
|
2518
|
+
|
|
2519
|
+
| Name | Min width |
|
|
2520
|
+
| ---- | --------- |
|
|
2521
|
+
| `s` | 600 px |
|
|
2522
|
+
| `m` | 993 px |
|
|
2523
|
+
| `l` | 1240 px |
|
|
2524
|
+
|
|
2525
|
+
Used by `.s` / `.m` / `.l` show-hide and the `.s1`–`.s12` / `.m1`–`.m12` / `.l1`–`.l12` grid spans.
|
|
2526
|
+
|
|
2527
|
+
---
|
|
2528
|
+
|
|
2529
|
+
## Authoring conventions
|
|
2530
|
+
|
|
2531
|
+
**Don't fight the framework.** md3 is opinionated by design: semantic HTML + a single component class + composable helpers + design-token overrides. If you find yourself reaching for BEM-style sub-element classes (`.card-header`, `.card-body`), wrapping every tag in extra divs, or writing custom CSS that re-implements a helper, stop — there's almost always a built-in helper for that. The framework is small (≈100 classes) precisely so you can hold all of it in your head and compose instead of layering.
|
|
2532
|
+
|
|
2533
|
+
If a helper doesn't exist for what you need, override a [design token](#design-tokens) at the scope you need it. That's the escape hatch — not a parallel class system.
|
|
2534
|
+
|
|
2535
|
+
Three rules keep markup predictable and styles composable.
|
|
2536
|
+
|
|
2537
|
+
### ✅ Do
|
|
2538
|
+
|
|
2539
|
+
```html
|
|
2540
|
+
<!-- One element + N helpers on the same tag -->
|
|
2541
|
+
<button class="border round large">…</button>
|
|
2542
|
+
<div class="field label border">…</div>
|
|
2543
|
+
|
|
2544
|
+
<!-- One <main> per document -->
|
|
2545
|
+
<body>
|
|
2546
|
+
<main class="responsive">…</main>
|
|
2547
|
+
</body>
|
|
2548
|
+
|
|
2549
|
+
<!-- Inline/block elements inside block elements -->
|
|
2550
|
+
<div>
|
|
2551
|
+
<div>block</div>
|
|
2552
|
+
<span>inline</span>
|
|
2553
|
+
</div>
|
|
2554
|
+
```
|
|
2555
|
+
|
|
2556
|
+
```css
|
|
2557
|
+
/* Helper composition */
|
|
2558
|
+
.button.border { … }
|
|
2559
|
+
|
|
2560
|
+
/* Direct-child component nesting */
|
|
2561
|
+
.field > input { … }
|
|
2562
|
+
.field > .max { … }
|
|
2563
|
+
```
|
|
2564
|
+
|
|
2565
|
+
### 🚫 Don't
|
|
2566
|
+
|
|
2567
|
+
```html
|
|
2568
|
+
<!-- N elements on one tag -->
|
|
2569
|
+
<div class="field button border">…</div>
|
|
2570
|
+
<button class="chip">…</button> <!-- NO, this collides;
|
|
2571
|
+
use .chip OR <button>, not both as elements -->
|
|
2572
|
+
|
|
2573
|
+
<!-- Custom sub-element class trees -->
|
|
2574
|
+
<div class="card">
|
|
2575
|
+
<div class="card-header">…</div>
|
|
2576
|
+
<div class="card-content">…</div>
|
|
2577
|
+
<div class="card-footer">…</div>
|
|
2578
|
+
</div>
|
|
2579
|
+
|
|
2580
|
+
<!-- Multiple <main> -->
|
|
2581
|
+
<body>
|
|
2582
|
+
<main>…</main>
|
|
2583
|
+
<main>…</main>
|
|
2584
|
+
</body>
|
|
2585
|
+
|
|
2586
|
+
<!-- Block inside inline -->
|
|
2587
|
+
<span>
|
|
2588
|
+
<div>…</div>
|
|
2589
|
+
</span>
|
|
2590
|
+
```
|
|
2591
|
+
|
|
2592
|
+
```css
|
|
2593
|
+
/* Don't double-class the same element type */
|
|
2594
|
+
.button.button { … }
|
|
2595
|
+
|
|
2596
|
+
/* Don't descend through unrelated elements */
|
|
2597
|
+
.button .chip { … }
|
|
2598
|
+
```
|
|
2599
|
+
|
|
2600
|
+
### Tips
|
|
2601
|
+
|
|
2602
|
+
1. Reach for [Helpers](#helpers) before writing custom CSS.
|
|
2603
|
+
2. To customize the theme, override the [Design tokens](#design-tokens).
|
|
2604
|
+
3. Quick-learn by scanning the per-component class tables.
|
|
2605
|
+
4. Slider value rendering, textarea auto-resize, and the file/color/password field wiring require the JS runtime. Theme/mode/dialog/menu/snackbar/page work via CSS + `data-ui`.
|
|
2606
|
+
5. For Vite users, build with `assetsInlineLimit: 0` so the bundled Material Symbols fonts aren't base64-inlined.
|
|
2607
|
+
|
|
270
2608
|
---
|
|
271
2609
|
|
|
272
|
-
##
|
|
2610
|
+
## Repository
|
|
273
2611
|
|
|
274
|
-
|
|
2612
|
+
https://github.com/stackific/md3 — Apache-2.0.
|