material 3.0.0-next.0 → 3.0.0-next.1

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.
Files changed (245) hide show
  1. package/README.md +55 -370
  2. package/dist/components/badge/index.d.ts +1 -1
  3. package/dist/components/badge/index.js +1 -1
  4. package/dist/components/button/index.d.ts +1 -1
  5. package/dist/components/button/index.js +1 -1
  6. package/dist/components/card/index.d.ts +1 -1
  7. package/dist/components/card/index.js +1 -1
  8. package/dist/components/checkbox/index.d.ts +1 -1
  9. package/dist/components/checkbox/index.js +1 -1
  10. package/dist/components/chips/index.d.ts +1 -1
  11. package/dist/components/chips/index.js +1 -1
  12. package/dist/components/datepicker/index.d.ts +1 -1
  13. package/dist/components/datepicker/index.js +1 -1
  14. package/dist/components/dialog/index.d.ts +1 -1
  15. package/dist/components/dialog/index.js +1 -1
  16. package/dist/components/divider/index.d.ts +1 -1
  17. package/dist/components/divider/index.js +1 -1
  18. package/dist/components/drawer/index.d.ts +1 -1
  19. package/dist/components/drawer/index.js +1 -1
  20. package/dist/components/list/index.d.ts +1 -1
  21. package/dist/components/list/index.js +1 -1
  22. package/dist/components/list/list.d.ts +13 -0
  23. package/dist/components/list/types.d.ts +14 -1
  24. package/dist/components/loading-indicator/index.d.ts +1 -1
  25. package/dist/components/loading-indicator/index.js +1 -1
  26. package/dist/components/menu/index.d.ts +1 -1
  27. package/dist/components/menu/index.js +1 -1
  28. package/dist/components/progress/index.d.ts +1 -1
  29. package/dist/components/progress/index.js +1 -1
  30. package/dist/components/progress/types.d.ts +20 -10
  31. package/dist/components/radios/index.d.ts +1 -1
  32. package/dist/components/radios/index.js +1 -1
  33. package/dist/components/search/index.d.ts +1 -1
  34. package/dist/components/search/index.js +1 -1
  35. package/dist/components/select/index.d.ts +1 -1
  36. package/dist/components/select/index.js +1 -1
  37. package/dist/components/slider/index.d.ts +1 -1
  38. package/dist/components/slider/index.js +1 -1
  39. package/dist/components/slider/types.d.ts +7 -0
  40. package/dist/components/snackbar/index.d.ts +1 -1
  41. package/dist/components/snackbar/index.js +1 -1
  42. package/dist/components/split-button/index.d.ts +1 -1
  43. package/dist/components/split-button/index.js +1 -1
  44. package/dist/components/switch/index.d.ts +1 -1
  45. package/dist/components/switch/index.js +1 -1
  46. package/dist/components/tabs/index.d.ts +1 -0
  47. package/dist/components/tabs/index.js +1 -0
  48. package/dist/components/tabs/types.d.ts +15 -3
  49. package/dist/components/text-field/features/placement.js +7 -4
  50. package/dist/components/timepicker/index.d.ts +1 -1
  51. package/dist/components/timepicker/index.js +1 -1
  52. package/dist/components/tooltip/index.d.ts +1 -1
  53. package/dist/components/tooltip/index.js +1 -1
  54. package/dist/core/compose/features/textinput.js +3 -1
  55. package/dist/core/compose/index.d.ts +1 -1
  56. package/dist/core/dom/html.d.ts +1 -1
  57. package/dist/elements/css/button.css +1 -1
  58. package/dist/elements/css/button.js +1 -1
  59. package/dist/elements/css/card.css +1 -1
  60. package/dist/elements/css/card.js +1 -1
  61. package/dist/elements/css/checkbox.css +1 -1
  62. package/dist/elements/css/checkbox.js +1 -1
  63. package/dist/elements/css/chips.css +1 -1
  64. package/dist/elements/css/chips.js +1 -1
  65. package/dist/elements/css/dialog.css +1 -1
  66. package/dist/elements/css/dialog.js +1 -1
  67. package/dist/elements/css/extended-fab.css +1 -1
  68. package/dist/elements/css/extended-fab.js +1 -1
  69. package/dist/elements/css/fab-menu.css +1 -1
  70. package/dist/elements/css/fab-menu.js +1 -1
  71. package/dist/elements/css/fab.css +1 -1
  72. package/dist/elements/css/fab.js +1 -1
  73. package/dist/elements/css/hosts/switch.css +1 -1
  74. package/dist/elements/css/hosts/text-field.css +1 -1
  75. package/dist/elements/css/icon-button.css +1 -1
  76. package/dist/elements/css/icon-button.js +1 -1
  77. package/dist/elements/css/list.css +1 -1
  78. package/dist/elements/css/list.js +1 -1
  79. package/dist/elements/css/menu.css +1 -1
  80. package/dist/elements/css/menu.js +1 -1
  81. package/dist/elements/css/radios.css +1 -1
  82. package/dist/elements/css/radios.js +1 -1
  83. package/dist/elements/css/select.css +1 -1
  84. package/dist/elements/css/select.js +1 -1
  85. package/dist/elements/css/side-sheet.css +1 -1
  86. package/dist/elements/css/side-sheet.js +1 -1
  87. package/dist/elements/css/slider.css +1 -1
  88. package/dist/elements/css/slider.js +1 -1
  89. package/dist/elements/css/snackbar.css +1 -1
  90. package/dist/elements/css/snackbar.js +1 -1
  91. package/dist/elements/css/switch.css +1 -1
  92. package/dist/elements/css/switch.js +1 -1
  93. package/dist/elements/css/text-field.css +1 -1
  94. package/dist/elements/css/text-field.js +1 -1
  95. package/dist/elements/define.d.ts +20 -0
  96. package/dist/elements/preupgrade/badge.css +1 -1
  97. package/dist/elements/preupgrade/bottom-app-bar.css +1 -1
  98. package/dist/elements/preupgrade/bottom-sheet.css +1 -1
  99. package/dist/elements/preupgrade/button-group.css +1 -1
  100. package/dist/elements/preupgrade/button.css +2 -2
  101. package/dist/elements/preupgrade/card.css +1 -1
  102. package/dist/elements/preupgrade/carousel.css +1 -1
  103. package/dist/elements/preupgrade/checkbox.css +2 -2
  104. package/dist/elements/preupgrade/chips.css +1 -1
  105. package/dist/elements/preupgrade/datepicker.css +1 -1
  106. package/dist/elements/preupgrade/dialog.css +1 -1
  107. package/dist/elements/preupgrade/divider.css +1 -1
  108. package/dist/elements/preupgrade/drawer.css +1 -1
  109. package/dist/elements/preupgrade/extended-fab.css +1 -1
  110. package/dist/elements/preupgrade/fab-menu.css +1 -1
  111. package/dist/elements/preupgrade/fab.css +1 -1
  112. package/dist/elements/preupgrade/icon-button.css +1 -1
  113. package/dist/elements/preupgrade/list.css +2 -2
  114. package/dist/elements/preupgrade/loading-indicator.css +1 -1
  115. package/dist/elements/preupgrade/menu.css +1 -1
  116. package/dist/elements/preupgrade/navigation-bar.css +1 -1
  117. package/dist/elements/preupgrade/navigation-rail.css +1 -1
  118. package/dist/elements/preupgrade/progress.css +1 -1
  119. package/dist/elements/preupgrade/radios.css +2 -2
  120. package/dist/elements/preupgrade/search.css +1 -1
  121. package/dist/elements/preupgrade/select.css +1 -1
  122. package/dist/elements/preupgrade/side-sheet.css +1 -1
  123. package/dist/elements/preupgrade/slider.css +1 -1
  124. package/dist/elements/preupgrade/snackbar.css +1 -1
  125. package/dist/elements/preupgrade/split-button.css +1 -1
  126. package/dist/elements/preupgrade/switch.css +2 -2
  127. package/dist/elements/preupgrade/tabs.css +1 -1
  128. package/dist/elements/preupgrade/text-field.css +2 -2
  129. package/dist/elements/preupgrade/timepicker.css +1 -1
  130. package/dist/elements/preupgrade/toolbar.css +1 -1
  131. package/dist/elements/preupgrade/tooltip.css +1 -1
  132. package/dist/elements/preupgrade/top-app-bar.css +1 -1
  133. package/dist/elements/preupgrade.css +2 -2
  134. package/dist/elements/preupgrade.js +1 -1
  135. package/dist/elements/styles.d.ts +13 -1
  136. package/dist/elements/switch.d.ts +1 -0
  137. package/dist/elements/switch.js +1 -0
  138. package/dist/elements/text-field.js +1 -5
  139. package/dist/package.json +28 -4
  140. package/dist/styles/badge.css +1 -1
  141. package/dist/styles/base.css +1 -1
  142. package/dist/styles/bottom-app-bar.css +1 -1
  143. package/dist/styles/bottom-sheet.css +1 -1
  144. package/dist/styles/button-group.css +1 -1
  145. package/dist/styles/button.css +2 -2
  146. package/dist/styles/card.css +2 -2
  147. package/dist/styles/carousel.css +1 -1
  148. package/dist/styles/checkbox.css +2 -2
  149. package/dist/styles/chips.css +2 -2
  150. package/dist/styles/contrast.css +1 -1
  151. package/dist/styles/datepicker.css +1 -1
  152. package/dist/styles/dialog.css +2 -2
  153. package/dist/styles/divider.css +1 -1
  154. package/dist/styles/drawer.css +1 -1
  155. package/dist/styles/extended-fab.css +2 -2
  156. package/dist/styles/fab-menu.css +2 -2
  157. package/dist/styles/fab.css +2 -2
  158. package/dist/styles/icon-button.css +2 -2
  159. package/dist/styles/list.css +2 -2
  160. package/dist/styles/loading-indicator.css +1 -1
  161. package/dist/styles/menu.css +2 -2
  162. package/dist/styles/navigation-bar.css +1 -1
  163. package/dist/styles/navigation-rail.css +1 -1
  164. package/dist/styles/progress.css +1 -1
  165. package/dist/styles/radios.css +2 -2
  166. package/dist/styles/search.css +1 -1
  167. package/dist/styles/select.css +2 -2
  168. package/dist/styles/side-sheet.css +2 -2
  169. package/dist/styles/slider.css +2 -2
  170. package/dist/styles/snackbar.css +2 -2
  171. package/dist/styles/split-button.css +1 -1
  172. package/dist/styles/switch.css +2 -2
  173. package/dist/styles/tabs.css +1 -1
  174. package/dist/styles/text-field.css +2 -2
  175. package/dist/styles/timepicker.css +1 -1
  176. package/dist/styles/toolbar.css +1 -1
  177. package/dist/styles/tooltip.css +1 -1
  178. package/dist/styles/top-app-bar.css +1 -1
  179. package/dist/styles/typography.css +1 -1
  180. package/dist/styles/utilities.css +1 -1
  181. package/dist/styles.css +2 -2
  182. package/dist/themes/autumn-contrast.css +1 -1
  183. package/dist/themes/autumn.css +1 -1
  184. package/dist/themes/baseline-contrast.css +1 -1
  185. package/dist/themes/baseline.css +1 -1
  186. package/dist/themes/brownbeige-contrast.css +1 -1
  187. package/dist/themes/brownbeige.css +1 -1
  188. package/dist/themes/content-contrast.css +1 -1
  189. package/dist/themes/content.css +1 -1
  190. package/dist/themes/desert-contrast.css +1 -1
  191. package/dist/themes/desert.css +1 -1
  192. package/dist/themes/expressive-contrast.css +1 -1
  193. package/dist/themes/expressive.css +1 -1
  194. package/dist/themes/fidelity-contrast.css +1 -1
  195. package/dist/themes/fidelity.css +1 -1
  196. package/dist/themes/forest-contrast.css +1 -1
  197. package/dist/themes/forest.css +1 -1
  198. package/dist/themes/fruit-salad-contrast.css +1 -1
  199. package/dist/themes/fruit-salad.css +1 -1
  200. package/dist/themes/highcontrast-contrast.css +1 -1
  201. package/dist/themes/highcontrast.css +1 -1
  202. package/dist/themes/monochrome-contrast.css +1 -1
  203. package/dist/themes/monochrome.css +1 -1
  204. package/dist/themes/neutral-contrast.css +1 -1
  205. package/dist/themes/neutral.css +1 -1
  206. package/dist/themes/ocean-contrast.css +1 -1
  207. package/dist/themes/ocean.css +1 -1
  208. package/dist/themes/rainbow-contrast.css +1 -1
  209. package/dist/themes/rainbow.css +1 -1
  210. package/dist/themes/sageivory-contrast.css +1 -1
  211. package/dist/themes/sageivory.css +1 -1
  212. package/dist/themes/spring-contrast.css +1 -1
  213. package/dist/themes/spring.css +1 -1
  214. package/dist/themes/summer-contrast.css +1 -1
  215. package/dist/themes/summer.css +1 -1
  216. package/dist/themes/sunset-contrast.css +1 -1
  217. package/dist/themes/sunset.css +1 -1
  218. package/dist/themes/tealcaramel-contrast.css +1 -1
  219. package/dist/themes/tealcaramel.css +1 -1
  220. package/dist/themes/vibrant-contrast.css +1 -1
  221. package/dist/themes/vibrant.css +1 -1
  222. package/package.json +28 -4
  223. package/src/styles/abstract/_mixins.scss +17 -5
  224. package/src/styles/abstract/_variables.scss +1 -1
  225. package/src/styles/components/_button.scss +10 -7
  226. package/src/styles/components/_checkbox.scss +10 -0
  227. package/src/styles/components/_chips.scss +10 -0
  228. package/src/styles/components/_dialog.scss +16 -0
  229. package/src/styles/components/_icon-button.scss +6 -0
  230. package/src/styles/components/_list.scss +43 -2
  231. package/src/styles/components/_menu.scss +8 -0
  232. package/src/styles/components/_radios.scss +22 -4
  233. package/src/styles/components/_select.scss +13 -29
  234. package/src/styles/components/_side-sheet.scss +22 -0
  235. package/src/styles/components/_slider.scss +3 -3
  236. package/src/styles/components/_switch.scss +19 -0
  237. package/src/styles/components/_text-field.scss +87 -321
  238. package/src/styles/elements/_button.scss +17 -1
  239. package/src/styles/elements/_checkbox.scss +16 -0
  240. package/src/styles/elements/_list.scss +6 -0
  241. package/src/styles/elements/_radios.scss +3 -2
  242. package/src/styles/elements/_switch.scss +52 -0
  243. package/src/styles/elements/_text-field.scss +21 -0
  244. package/dist/LICENSE +0 -21
  245. package/dist/README.md +0 -438
package/README.md CHANGED
@@ -1,99 +1,44 @@
1
1
  # material
2
2
 
3
- Material Design 3 components for the web: as plain JavaScript, as web components, and as React, Vue, Svelte and Solid components. Written in TypeScript, with zero dependencies.
3
+ Material Design 3 components for the web: as web components, as React, Vue, Svelte and Solid components, and as plain JavaScript. Written in TypeScript, with zero dependencies.
4
4
 
5
- material implements the M3 Expressive update: component sizes, shapes, colours and spring motion follow the Material 3 tokens. One implementation serves every way of using it, so a button looks and behaves the same in each. The documentation site, [md3.io](https://md3.io), has a live playground and examples in every framework for each component.
5
+ - **Material 3 Expressive.** Component sizes, shapes, colours and spring motion follow the Material 3 tokens.
6
+ - **One implementation, every stack.** A button looks and behaves the same as an element, as a framework component and as a factory.
7
+ - **Zero dependencies.** Installing `material` installs nothing else; the frameworks are optional peers.
8
+ - **Server rendering.** Elements and framework components render to declarative shadow DOM on Node and Bun.
9
+ - **Measured sizes.** A size budget per component, enforced on every pull request.
10
+
11
+ Documentation, a live playground and examples in every framework: **[md3.io](https://md3.io)**.
6
12
 
7
13
  ## Install
8
14
 
15
+ <!-- install -->
9
16
  ```bash
10
- npm install material
17
+ npm install material@next
11
18
  ```
12
19
 
13
- React, Vue, Svelte and Solid are optional peer dependencies: material uses the one your app has and installs none of them.
14
-
15
- ## Use it your way
20
+ 3.0.0 is in pre-release, on the `next` tag. Until it is released, `npm install material` without the tag installs 1.0.4, an earlier and separate library (see [Where this came from](#where-this-came-from)).
21
+ <!-- /install -->
16
22
 
17
- | Way | Import from | Good for |
18
- |-----|-------------|----------|
19
- | Web components | `material/elements` | Plain HTML, server templates, Angular, any framework |
20
- | React | `material/react` | React 18 and 19, Next.js |
21
- | Vue | `material/vue` | Vue 3, Nuxt |
22
- | Svelte | `material/svelte` | Svelte 5, SvelteKit |
23
- | Solid | `material/solid` | SolidJS, SolidStart |
24
- | Vanilla factories | `material` | The smallest bundles and full control |
25
-
26
- Every app imports the base stylesheet once: the theme, the tokens a component reads, and the ripple. Type classes and the type scale are `material/styles/typography` (see [Styles](#styles)).
27
-
28
- ```typescript
29
- import 'material/styles/base';
30
- ```
31
-
32
- **Web components**: register them once, then write HTML.
33
-
34
- ```html
35
- <script type="module">
36
- import 'material/styles/base';
37
- import 'material/elements/css';
38
- import { defineAll } from 'material/elements';
39
- defineAll();
40
- </script>
41
-
42
- <form>
43
- <m-text-field name="email" type="email" label="Email" required></m-text-field>
44
- <m-switch name="news" checked>Newsletter</m-switch>
45
- <m-button type="submit">Sign up</m-button>
46
- </form>
47
- ```
48
-
49
- **React** (Vue, Svelte and Solid work the same way, see [below](#react-vue-svelte-and-solid)):
50
-
51
- ```tsx
52
- import 'material/styles/base';
53
- import { Button, Switch, TextField } from 'material/react';
54
-
55
- export function Signup() {
56
- return (
57
- <form>
58
- <TextField name="email" type="email" label="Email" required />
59
- <Switch name="news" defaultChecked>Newsletter</Switch>
60
- <Button type="submit">Sign up</Button>
61
- </form>
62
- );
63
- }
64
- ```
65
-
66
- **Vanilla**: each component is a function that returns a DOM element and a small API.
23
+ ## Quick start
67
24
 
25
+ <!-- example: run, shows "Save" -->
68
26
  ```typescript
69
27
  import 'material/styles';
70
28
  import { createButton, createTextField } from 'material';
71
29
 
72
30
  const name = createTextField({ label: 'Name' });
73
31
  const save = createButton({ text: 'Save', variant: 'filled' });
74
- save.disabled.disable();
75
32
 
76
- name.on('input', ({ value }: { value: string }) => {
77
- if (value.trim()) save.disabled.enable();
78
- else save.disabled.disable();
79
- });
80
33
  save.on('click', () => console.log('Saved', name.getValue()));
81
34
 
82
35
  document.body.append(name.element, save.element);
83
-
84
- // When the view goes away, release listeners and DOM
85
- name.destroy();
86
- save.destroy();
87
36
  ```
88
37
 
89
- Two rules hold for every factory's events. A config `on*` option (`onChange`, `onOpen`, …) is the listener registered at creation: it gets the same argument as a listener passed to `on()`, and runs before one added later. And when `open()` or `close()` returns, the state has changed (`isOpen()`) and the event has been emitted, a cancellable `beforeopen` or `beforeclose` first where the component has one; the classes, the paint, focus and the animation may follow, so add an `open` listener before calling `open()`. Opening an open component, or closing a closed one, does nothing and emits nothing. Every overlay follows this second rule (the snackbar with `show()` and `hide()`, the split button with `expand()` and `collapse()`); a surface loaded on demand, such as the FAB menu's menu, may be painted after `open()` returns. The event that opened an overlay never dismisses it: it ignores exactly the event whose dispatch had begun when `open()` ran, and nothing later. Escape is a key press for every modal (the dialog, the modal sheets and drawer, the pickers, the full-screen search): only the topmost one answers, and a refusal (`closeOnEscape: false`, a `beforeclose` that refuses, a drawer that is not `dismissible`) holds for any number of presses; only a close request that is not a key press, such as a back gesture, can still be forced by the browser, on its third refusal. On the elements, the `open` attribute and property are applied at once and dispatch nothing; `open` and `close` are dispatched when a method or the user opens or closes. The tooltip is outside the second rule, by design: its `show()` and `hide()` wait for their delays (300 and 100 ms unless called with `true`) and emit no event; read `isVisible()`. The state getter is a method on every component that has one: `isOpen()` on the dialog, the menu, the select, the FAB menu, the sheets, the drawer, the snackbar and both pickers; `isExpanded()` on the search, the split button, the navigation rail and the card; `isVisible()` on the tooltip, the bottom app bar and the toolbar; `isHidden()` on the navigation bar.
90
-
91
- The factories are the fastest way to render hundreds of components at once, such as a long editable table; the elements style a shadow root each. `material/styles` loads every component's styles; for a smaller bundle, import only what you use (see [Styles](#styles)).
38
+ `material/styles` is a stylesheet, so this needs a bundler that handles CSS imports (Vite, webpack, Bun, …). Each factory returns a DOM element and a small API; call `destroy()` when the view goes away.
92
39
 
93
40
  ## Components
94
41
 
95
- Every component comes three ways: a factory (`createButton`), an element (`<m-button>`) and a framework component (`Button`; `MButton` in Vue).
96
-
97
42
  | Group | Components |
98
43
  |-------|------------|
99
44
  | Actions | Button, Icon button, Button group, Split button, FAB, Extended FAB, FAB menu, Toolbar |
@@ -102,337 +47,77 @@ Every component comes three ways: a factory (`createButton`), an element (`<m-bu
102
47
  | Containment | Card, Carousel, List, Divider, Dialog, Bottom sheet, Side sheet |
103
48
  | Communication | Badge, Progress, Loading indicator, Snackbar, Tooltip |
104
49
 
105
- The factories are exported from `material`: `createButton`, `createIconButton`, `createButtonGroup`, `createSplitButton`, `createFab`, `createExtendedFab`, `createFabMenu`, `createToolbar`, `createCheckbox`, `createSwitch`, `createRadios`, `createChips` (with `createAssistChip`, `createFilterChip`, `createInputChip` and `createSuggestionChip`), `createSlider`, `createTextField`, `createSelect`, `createSearch`, `createDatePicker`, `createTimePicker`, `createNavigationRail`, `createDrawer`, `createTabs` and `createTab`, `createMenu`, `createTopAppBar`, `createBottomAppBar`, `createCard` (with `createCardHeader`, `createCardContent`, `createCardMedia` and `createCardActions`), `createCarousel`, `createList`, `createDivider`, `createDialog`, `createBottomSheet`, `createSideSheet`, `createBadge`, `createProgress`, `createLoadingIndicator`, `createSnackbar` and `createTooltip`.
106
-
107
- ## Styles
108
-
109
- The web components and the framework components carry their own styles in their shadow roots; they need only the base stylesheet, `material/styles/base`, for the theme and its tokens. The factories render in the page, so they use the page's stylesheets. Import the full stylesheet once:
110
-
111
- ```typescript
112
- import 'material/styles';
113
- ```
114
-
115
- Or import the base once, followed by the components you use:
116
-
117
- ```typescript
118
- import 'material/styles/base';
119
- import 'material/styles/button';
120
- import 'material/styles/text-field';
121
-
122
- // Optional: an alternate theme and the utility classes
123
- import 'material/themes/ocean';
124
- import 'material/styles/utilities';
125
- ```
126
-
127
- The base includes the baseline theme in light and dark, the colour, shape and typeface tokens, the three body-medium type tokens the page's text reads (`--mtrl-sys-typescale-body-medium-font`, `-font-size` and `-line-height`), a reset and the ripple. The type classes (`.mtrl-display-large` through `.mtrl-label-small`), the text utilities (`.mtrl-text-*`, `.mtrl-font-*`, `.mtrl-truncate*`), material's styles for `h1`–`h6` and `p`, and the rest of the type scale are a separate import:
128
-
129
- ```typescript
130
- import 'material/styles/typography';
131
- ```
132
-
133
- It has to load after the base: both sheets style `h1`–`h6` and `p`, and the later one wins. The import above takes care of it (the module imports `material/styles/base` first, in whatever order your own imports are). If your bundler splits the two into different chunks, make sure the base's CSS loads first: an import order is not a CSS order in every bundler. With `<link>` tags, put `dist/styles/typography.css` after `dist/styles/base.css`.
134
-
135
- Import it when the page uses those classes or utilities, when it relies on material's heading and paragraph styles, or when its own CSS reads a `--mtrl-sys-typescale-*` token. Without it a `.mtrl-headline-small` element keeps the body's font size, and a `var(--mtrl-sys-typescale-*)` with no fallback is invalid at computed-value time. Body text keeps its font. The full stylesheet includes typography, so `import 'material/styles'` is unchanged.
136
-
137
- Each selective entry imports what it depends on (the select brings the text field and the menu), so use a CSS-capable bundler to resolve and deduplicate them. Choose either the full stylesheet or selective imports, not both. The `material/styles/*` entries are bundler targets: they import CSS, so they do not load in plain Node.
138
-
139
- Library styles sit in ordered `mtrl.*` cascade layers, so unlayered application CSS overrides them without specificity battles.
140
-
141
- The Sass sources ship for reference; configuring them with `@use … with` is not a supported API in `material` 3.0.0. Theme with CSS custom properties.
142
-
143
- ### Themes
144
-
145
- The baseline theme applies by default and follows the system light or dark preference. Choose a theme and mode on the root element:
146
-
147
- ```html
148
- <html data-theme="ocean" data-theme-mode="dark">
149
- ```
150
-
151
- ```typescript
152
- document.documentElement.dataset.theme = 'ocean';
153
- document.documentElement.dataset.themeMode = 'dark';
154
- ```
155
-
156
- Available themes: `baseline`, `ocean`, `desert`, `forest`, `sunset`, `spring`, `summer`, `autumn`, `brownbeige`, `sageivory`, `tealcaramel` and `highcontrast`. With selective styles, import the theme's entry, for example `material/themes/ocean`.
157
-
158
- Every theme supports `data-theme-contrast="standard"`, `"medium"` and `"high"` on the same element as `data-theme` and `data-theme-mode`. The attribute is opt-in: the full stylesheet includes it, and selective styles add `material/styles/contrast` for the baseline theme, or `material/themes/<name>-contrast` beside `material/themes/<name>`. Without that import the attribute changes no colour. The OS preference does not need an import.
159
-
160
- ```html
161
- <html data-theme="desert" data-theme-mode="dark" data-theme-contrast="high">
162
- ```
163
-
164
- ```typescript
165
- import 'material/styles/base';
166
- import 'material/styles/contrast';
167
- import 'material/themes/desert';
168
- import 'material/themes/desert-contrast';
169
- ```
170
-
171
- Import `material/styles/contrast` after `material/styles/base`, as with `material/styles/typography`: the opt-in sheets share the base cascade layer, so their order inside it matters. Typography's heading margins depend on that order. The contrast sheet's colours do not: an explicit level is a more specific selector than the standard rule, and `prefers-contrast: more` is guarded by `:not([data-theme-contrast])`, so either load order resolves the same colours.
172
-
173
- Without `data-theme-contrast`, `prefers-contrast: more` selects high contrast on every themed element independently. An explicit `standard` opts out on that element; `medium` overrides the preference too. Contrast settings do not inherit from an ancestor across a nested theme: put `data-theme-contrast` on the same element as each `data-theme`, including nested sections. For example, opting out on the root does not opt out a nested theme without its own `data-theme-contrast="standard"`. `data-theme-contrast` is read on the element that carries `data-theme`, or on the root when the page has no `data-theme`; on any other element it does nothing (that element inherits its themed ancestor's level).
174
-
175
- The default baseline also supports this setting without `data-theme`. On that unthemed root, both standard and higher contrast follow the OS color scheme and `.dark-theme`, ignoring `data-theme-mode`. Medium and high use M3 contrast levels 0.5 and 1.0; hand-authored themes derive them with Tonal Spot from their documented seed (falling back to their light primary), preserving their light secondary and tertiary hues and chroma. Neutral palettes come from the seed, while standard colors stay unchanged. Success, warning and info keep their existing status colors. The `highcontrast` theme is a theme in its own right and supports all three contrast settings.
176
-
177
- M3's scheme variants, generated from the baseline seed, ship as their own entries only (not in the full stylesheet): `neutral`, `vibrant`, `expressive`, `fidelity`, `content`, `monochrome`, `rainbow` and `fruit-salad`, for example `material/themes/vibrant`. `schemeToTokens` (`material/core/theme`) turns any M3 scheme's role colours into these tokens.
178
-
179
- ### Custom properties
180
-
181
- Components read the theme's colour roles, so overriding a role restyles every component that uses it:
182
-
183
- ```css
184
- :root {
185
- --mtrl-sys-color-primary: #6750a4;
186
- --mtrl-sys-color-on-primary: #ffffff;
187
- }
188
- ```
189
-
190
- The typefaces and the corner scale are custom properties on the base (`--mtrl-ref-typeface-brand`, `--mtrl-ref-typeface-plain`, `--mtrl-sys-shape-corner-*`): setting one on `:root` restyles every component that uses it. The type scale (`--mtrl-sys-typescale-*`) ships in `material/styles/typography` and in the full stylesheet; setting a role's size there restyles the type classes and the heading styles. Component hooks follow one convention, `--mtrl-<component>-<name>`:
191
-
192
- ```css
193
- .brand-slider {
194
- --mtrl-slider-color: #006a6a;
195
- --mtrl-slider-on-color: #ffffff;
196
- }
197
- ```
50
+ Every component comes three ways: a factory, a custom element and a framework component. Each has a page with a playground on [md3.io/components](https://md3.io/components/).
198
51
 
199
52
  ## Web components
200
53
 
201
- Overlays open in the browser's top layer (`showModal()` or `popover`) from inside their own shadow root, so they keep their styles, trap focus and make the page inert where M3 says so. Form controls are form-associated: `name`, the form value, reset, validation, `<label for>` and back-navigation restore work as on native controls.
202
-
203
- Declaration children describe a component's items, as native `<select>` and `<option>` do:
204
-
205
- ```html
206
- <m-tabs value="songs">
207
- <m-tab value="songs">Songs</m-tab>
208
- <m-tab value="albums">Albums</m-tab>
209
- </m-tabs>
210
- ```
211
-
212
- The page still loads material's base styles and a theme (see [Styles](#styles)); the elements render in shadow DOM and pick up the theme's tokens. Attributes are defaults and properties the live state, as on native controls: a `checked` or `value` attribute sets the state until the user or a script changes it, and `form.reset()` goes back to it. Form controls take part in forms (their host's `name`), reset, validation and back-navigation restore.
213
-
214
- A server-rendered page sends each element as its tag and light DOM; the element takes its real look once its script defines it. Nothing reserves that box unless the pre-upgrade stylesheet is in `<head>`, after material's base styles and theme. It gives every element not defined yet the box it will have (and its label the final type style), hides what it declares (`<m-tab>`, `<m-menu-item>`, …) and overlays. Its rules match only `:not(:defined)`, in the `mtrl.preupgrade` cascade layer. Without the stylesheet, an element has no reserved box until it is defined.
215
-
216
- ```html
217
- <link rel="stylesheet" href="/node_modules/material/dist/elements/preupgrade.css">
218
- ```
54
+ A page imports the base stylesheet and the elements' CSS once, then registers the elements with `defineAll()`. After that `<m-button>` and the rest are HTML, in plain pages, server templates and any framework.
219
55
 
220
- A page that uses one element can load that element's file instead: `material/elements/preupgrade/<name>.css`, named by the spec (`text-field`, `select`, `icon-button`). Each file is that element's rules in the same `@layer mtrl.preupgrade`. With a bundler, `import 'material/elements/preupgrade.css'` or `import 'material/elements/preupgrade/button.css'`.
221
-
222
- With another tag prefix, `preupgradeStyles('x')` from `material/elements/preupgrade` returns the whole stylesheet for `<x-*>`, to inline on the server. The element CSS modules do not apply these rules.
56
+ Form controls are form-associated: the form value, reset and validation work as on native controls. Overlays open in the browser's top layer. Guide: [md3.io/docs/web-components](https://md3.io/docs/web-components/).
223
57
 
224
58
  ## React, Vue, Svelte and Solid
225
59
 
226
- The framework components render the elements, so everything above holds: forms, the top layer, the styling. `material/react`, `material/vue`, `material/svelte` and `material/solid` load the elements' CSS and register each element the first time it mounts.
227
-
228
- | Framework | Import | Two-way binding |
229
- |-----------|--------|-----------------|
230
- | React 18 and 19 | `import { Switch } from 'material/react'` | `checked` + `onChange`, or `defaultChecked` |
231
- | Vue 3 | `import { MSwitch } from 'material/vue'` | `v-model` |
232
- | Svelte 5 | `import { Switch } from 'material/svelte'` | `bind:checked` |
233
- | Solid | `import { Switch } from 'material/solid'` | `checked` + `onChange` |
234
-
235
- The `material/svelte` entry is a bundler target too: it imports `.svelte` files, so it does not load in plain Node.
236
-
237
- With `skipLibCheck: false`, use `@types/react` 18.2.71 or later.
238
-
239
- Each framework is an optional peer dependency; material installs none of them. All adapters render on the server and hydrate. Angular apps use the elements directly, with `CUSTOM_ELEMENTS_SCHEMA`.
60
+ | Framework | Import | Guide |
61
+ |-----------|--------|-------|
62
+ | React 18 and 19 | `import { Switch } from 'material/react'` | [md3.io/docs/react](https://md3.io/docs/react/) |
63
+ | Vue 3 | `import { MSwitch } from 'material/vue'` | [md3.io/docs/vue](https://md3.io/docs/vue/) |
64
+ | Svelte 5 | `import { Switch } from 'material/svelte'` | [md3.io/docs/svelte](https://md3.io/docs/svelte/) |
65
+ | Solid | `import { Switch } from 'material/solid'` | [md3.io/docs/solid](https://md3.io/docs/solid/) |
240
66
 
241
- A component owns the `on…` props of its element's events (`onChange`, `onInput`, `onSelect`, …) and its `default…` props, typed with the element's own payloads. Any other HTML attribute passes to the host; to spread a whole set of HTML attributes into a component, omit the props it owns (`Omit<React.HTMLAttributes<HTMLElement>, "onChange">`).
242
-
243
- Each framework has a guide on [md3.io](https://md3.io/docs/): props and events, controlled and uncontrolled state, named slots, refs and server rendering.
67
+ The framework components render the elements, load their CSS and register each one the first time it mounts. An app imports `material/styles/base` once for the theme. Each framework is an optional peer dependency: `material` uses the one your app has.
244
68
 
245
69
  ## Server rendering
246
70
 
247
- `renderElement` from `material/ssr` renders an element to declarative shadow DOM. Import `material/ssr/react`, `material/ssr/vue`, `material/ssr/svelte` or `material/ssr/solid` in the server bootstrap and that framework's components emit the same roots. Node and Bun are supported in `material` 3.0.0. Before upgrade, each toolbar item is its own tab stop; after upgrade, the toolbar is one.
248
-
249
- **Styles: inline by default.** Each root carries its whole CSS as a `<style>`, so it is styled at first paint in every engine with no extra request. That has two costs:
250
-
251
- - **How well it compresses depends on the compressor.** gzip cannot see a repeat further back than its 32 KB window. A select's root is about 44 KB of style text, so gzip never finds the previous select: 30 selects measured 141.0 KB with gzip against 5.0 KB with brotli. Smaller roots compress well when the same element repeats (30 buttons, at 16 KB a root: 6.4 KB with gzip; 30 dialogs: 10.3 KB), and badly when large roots of different types alternate, because the previous copy of each is then out of the window: selects, text fields, dialogs and buttons in turn measured 83.9 KB with gzip against 8.1 KB with brotli. Serve brotli, or use link mode for pages with many selects, or that mix large roots (text fields, dialogs) in turn.
252
- - **Uncompressed it is large:** 0.5 to 0.9 MB for 30 to 44 roots (489 KB for 30 buttons, 671 KB for a list page of 44 roots, 878 KB for the 30 large roots). That matters for anything that stores or streams the HTML uncompressed.
253
-
254
- **Link mode** (`renderElement(tag, attributes, children, { styles: 'link', cssBase: '/css' })`, with `dist/elements/css` served at that base) writes `<link>` tags in place of the style text: the same pages are 15 to 40 KB of HTML, and the stylesheets are fetched once and cached. Its caveat: WebKit paints the roots unstyled until the stylesheets arrive (about 470 ms with each stylesheet 300 ms away; a preload in the head does not help), where Chromium and Firefox wait for them before painting.
255
-
256
- Measured on Playwright's engines (Chromium 153, Firefox 155, WebKit 26.6); sizes are of the HTML `renderElement` returns, gzip at level 9, brotli at its default.
257
-
258
- A framework page that server-renders without that bridge (Next.js, Nuxt, SvelteKit, SolidStart) does not reserve an element's box between the HTML and hydration. Put the `<link>` above in `<head>` (or import the stylesheet). The link reserves the box from the first paint, before any script. The overlap, a pre-upgrade rule painting over a host that already has a shadow root, shows only when that page also loads the stylesheet.
259
-
260
- `renderElement`, and each bridge when it emits a shadow root, writes `data-mtrl-ssr` on that host. The stylesheet's last rule, in `mtrl.preupgrade`, matches that attribute and `:not(:defined)` (and the same for `::before`, `::after`, and a direct child that is not itself an element waiting to upgrade) at a higher specificity than any pre-upgrade selector of that subject, and sets `all: revert-layer`, so the stylesheet does not style a host the server already rendered, or those children. The attribute stays after upgrade. `:not(:defined)` no longer matches, so it does nothing. Carousel and the FAB menu opt out of the shadow root and do not carry the attribute: the stylesheet still reserves their box. A page without the bridge does not write the attribute. A Vue menu or split button that opts out of server rendering and has an async child shows its raw items until upgrade when the page also loads the pre-upgrade stylesheet.
71
+ `renderElement` from `material/ssr` renders an element to declarative shadow DOM. Each framework has a bridge, such as `material/ssr/react`, that makes its components emit the same roots and hydrate.
261
72
 
262
- Worker and edge runtimes are unsupported in `material` 3.0.0. Each server entry lists the `browser` condition first. A resolver that tries `workerd` or `worker` before `browser` (Cloudflare Workers does) loads the browser stub: `renderElement` throws "material/ssr is server-only", and importing a bridge does nothing, so the page renders with no declarative roots and no error.
73
+ Node and Bun are supported; worker and edge runtimes are not supported in `material` 3.0.0. Guide: [md3.io/docs/server-rendering](https://md3.io/docs/server-rendering/).
263
74
 
264
- The React bridge suppresses React's hydration warning on a rendered host, because the server adds `data-mtrl-ssr`; a host attribute that differs between server and client is therefore not reported by React.
75
+ ## Themes
265
76
 
266
- With `material/ssr/react`, put a `Suspense` boundary outside the component when its server-rendered shadow root needs the resolved child. A boundary inside the component contributes its fallback to that root: a button with an empty fallback has no label slot, while a text fallback gives it a slot and shows the fallback text. In tabs, a boundary around a tab leaves the server-rendered root without that tab with either fallback; a boundary inside a tab label keeps the tab, with an empty or fallback-text label.
77
+ The baseline theme applies by default and follows the system light or dark preference. Eleven more are in the full stylesheet, each in light and dark, with three contrast levels:
267
78
 
268
- With `material/ssr/react` and `material/ssr/svelte`, the server-rendered shadow root is built in a separate render, without the context of providers above the component. The page's own render (the light DOM) sees the provided value. Until the component upgrades, a child reading context with a default shows that default in the painted shadow root; a child requiring its context leaves that component without a declarative shadow root, while the page still renders. React and Svelte each log a development-only warning naming the element in the latter case. Keep context-dependent text outside material components: pass the resolved string as a prop or attribute, or accept client-rendered text until the upgrade. A fix is planned for a later 3.x release (FLO-517). The Vue and Solid bridges see the provided value in both the shadow root and light DOM.
269
-
270
- The same HTML policy as [Markup and sanitizing](#markup-and-sanitizing) applies to `material/ssr` and the four bridges.
271
-
272
- ## Imports and tree-shaking
273
-
274
- material publishes ESM only, with type declarations, so bundlers drop unused exports and split dynamic imports. From CommonJS, load it with a dynamic `import('material')`.
275
-
276
- | Import | Path |
277
- |--------|------|
278
- | Component creators | `import { createButton } from 'material'` |
279
- | One component directly | `import createSlider from 'material/components/slider'` |
280
- | Component constants | `import { BUTTON_VARIANTS } from 'material/components/button/constants'` |
281
- | Core utilities | `import { addClass, removeClass } from 'material/core/dom'` |
282
-
283
- Constants are not exported from the root; import them from the component's `constants` entry:
284
-
285
- ```typescript
286
- import { createButton } from 'material';
287
- import { BUTTON_VARIANTS, BUTTON_SIZES } from 'material/components/button/constants';
288
-
289
- const button = createButton({
290
- text: 'Submit',
291
- variant: BUTTON_VARIANTS.FILLED,
292
- size: BUTTON_SIZES.L,
293
- });
79
+ ```html
80
+ <html data-theme="ocean" data-theme-mode="dark">
294
81
  ```
295
82
 
296
- Some parts load on demand: a button's progress indicator, a card's action buttons, a menu's submenus and the FAB menu's desktop menu. Enable code splitting in your build to keep them out of the initial chunk.
83
+ Colours, typefaces and shapes are CSS custom properties (`--mtrl-sys-color-primary`, …), so one declaration restyles every component that reads it. Guide: [md3.io/docs/theming](https://md3.io/docs/theming/); the themes side by side: [md3.io/styles/themes](https://md3.io/styles/themes/).
297
84
 
298
- ## Building your own components
85
+ ## Sizes
299
86
 
300
- Components are composed from small features with `pipe`. The same building blocks are public:
87
+ What a bundler keeps, minified and gzipped (kB is 1,000 bytes), measured from the packed package. The table is refreshed at each release, and CI keeps every figure within 2% of the current build:
301
88
 
302
- ```typescript
303
- import { pipe, createBase, withEvents, withElement } from 'material/core/compose';
304
-
305
- const createNote = (config: { text?: string } = {}) =>
306
- pipe(
307
- createBase,
308
- withEvents(),
309
- withElement({ tag: 'div', componentName: 'note' }),
310
- (component) => ({
311
- ...component,
312
- setText(text: string) {
313
- component.element.textContent = text;
314
- },
315
- })
316
- )(config);
317
-
318
- // The component's type is what the pipe builds
319
- type NoteComponent = ReturnType<typeof createNote>;
320
-
321
- const note: NoteComponent = createNote();
322
- note.setText('Saved');
323
- document.body.append(note.element);
324
- ```
89
+ <!-- sizes -->
90
+ | Import | gzip |
91
+ |--------|-----:|
92
+ | `createButton` from `material`, with code splitting: the initial chunks (the progress indicator loads on demand) | 7.4 kB |
93
+ | `createButton`, without code splitting (the progress indicator included) | 13.7 kB |
94
+ | `createButton`, `createTextField` and `createCheckbox`, without code splitting | 19.9 kB |
95
+ | Everything the root exports (`export * from 'material'`), without code splitting | 126.9 kB |
96
+ | `material/styles/base` | 2.9 kB |
97
+ | `material/styles/base` and `material/styles/button` | 5.2 kB |
98
+ | `material/styles`, the full stylesheet | 61.8 kB |
99
+ <!-- /sizes -->
325
100
 
326
- The element gets the `mtrl-note` class, `withEvents` adds `on`, `off` and `emit`, and `destroy()` removes the element. Add `withLifecycle()` from `material/core/compose/features` when features need to register cleanup.
101
+ `material` publishes ESM only, so bundlers drop what you do not import. Each component's page on [md3.io/components](https://md3.io/components/) gives its size.
327
102
 
328
- ## Markup and sanitizing
329
-
330
- Icons and `content` options are markup strings, written with `innerHTML`. Every such write goes through one sink, so you can decide once how markup is treated. Set a policy when the strings can come from users or a CMS, or when your page enforces Trusted Types:
331
-
332
- ```typescript
333
- import { configureHTML } from 'material';
103
+ ## Browser support
334
104
 
335
- // A sanitizer
336
- configureHTML({ sanitize: (html) => DOMPurify.sanitize(html) });
105
+ Current Chrome, Edge, Firefox and Safari. The spring motion uses CSS `linear()` easing (Safari 17.2 or later); older browsers render every component but skip those transitions.
337
106
 
338
- // Trusted Types: under `require-trusted-types-for 'script'` a plain string
339
- // assignment throws, so return a TrustedHTML from a policy your CSP allows
340
- const policy = window.trustedTypes.createPolicy('mtrl', {
341
- createHTML: (html) => DOMPurify.sanitize(html),
342
- });
343
- configureHTML({ sanitize: (html) => policy.createHTML(html) });
344
- ```
107
+ ## Upgrading
345
108
 
346
- The policy sees every string, the library's own icons included; a `TrustedHTML` value passed as an icon or content skips it. With no policy set, markup is written as it is. Text options (`text`, a card's `text`) never go through `innerHTML`.
347
-
348
- These attributes are markup. With no policy set they are written as HTML, in the browser and when `material/ssr` or one of the four bridges renders the element. `avatar` and `leading-avatar` are not a person's name or an image URL.
349
-
350
- <!-- markup-attributes -->
351
-
352
- On the element:
353
-
354
- - `icon` on `<m-button>`
355
- - `icon` on `<m-extended-fab>`
356
- - `icon` on `<m-fab>`
357
- - `icon` on `<m-icon-button>`
358
- - `selected-icon` on `<m-icon-button>` — while `toggle` and `selected`
359
- - `expand-icon` on `<m-navigation-rail>` — while the rail is collapsed
360
- - `collapse-icon` on `<m-navigation-rail>` — while the rail is expanded
361
- - `leading-icon` on `<m-search>`
362
- - `trailing-icon` on `<m-search>`
363
- - `avatar` on `<m-search>` — not a person's name or an image URL
364
- - `icon` on `<m-slider>`
365
- - `inset-icon` on `<m-slider>` — size M, L or XL, not a range or centred slider, when the track can hold it
366
- - `inset-icon-at-min` on `<m-slider>` — the same, while the value is at the minimum
367
- - `icon` on `<m-split-button>`
368
- - `icon` on `<m-switch>`
369
- - `leading-icon` on `<m-text-field>`
370
- - `trailing-icon` on `<m-text-field>`
371
-
372
- On a declaration child:
373
-
374
- - `icon` on `<m-button-group-item>`
375
- - `selected-icon` on `<m-button-group-item>` — an icon-only item, while selected
376
- - `icon` on `<m-chip>`
377
- - `trailing-icon` on `<m-chip>`
378
- - `avatar` on `<m-chip>` — input chips only, and it takes precedence over `icon`; not a person's name or an image URL
379
- - `icon` on `<m-drawer-item>`
380
- - `leading-icon` on `<m-list-item>`
381
- - `leading-avatar` on `<m-list-item>` — not a person's name or an image URL
382
- - `trailing-icon` on `<m-list-item>`
383
- - `icon` on `<m-menu-item>`
384
- - `icon` on `<m-navigation-bar-item>`
385
- - `selected-icon` on `<m-navigation-bar-item>` — while that destination is active
386
- - `icon` on `<m-navigation-rail-item>`
387
- - `selected-icon` on `<m-navigation-rail-item>` — while that destination is active
388
- - `icon` on `<m-search-suggestion>`
389
- - `icon` on `<m-select-option>` — written into the menu
390
- - `icon` on `<m-tab>`
391
-
392
- `<m-fab-menu>` and `<m-fab-menu-item>` `icon` are markup too. The menu opts out of server rendering, so the server leaves those attributes escaped, and the same policy applies when the component upgrades.
393
-
394
- <!-- /markup-attributes -->
109
+ Upgrade to the latest `mtrl` 0.10.x first, then change the package name to `material` and follow the [migration guide](https://github.com/floor/material/blob/main/CHANGELOG.md#migrating-from-010x).
395
110
 
396
111
  ## Where this came from
397
112
 
398
- The package was published as `mtrl` up to 0.10.x. The history before 3.0.0 was developed in
399
- `floor/mtrl`; `#numbers` in commit subjects before 3.0.0 refer to
400
- [pull requests there](https://github.com/floor/mtrl/pulls?q=is%3Apr+is%3Aclosed).
401
-
402
- Versions of `material` up to 1.0.4 are an earlier, separate library (GPL-3). Its code is on the
403
- `v1` branch of this repository, and it stays installable with `npm install material@legacy`.
404
-
405
- What a page meets keeps the name: the `mtrl-` class prefix, the `--mtrl-` custom properties,
406
- the `m-` tags and the `mtrl.*` cascade layers are unchanged.
407
-
408
- ## Upgrading from `mtrl` 0.10
409
-
410
- `material` 3.0.0 removes what 0.10 deprecated. Upgrade to the latest `mtrl` 0.10.x first: it has the 3.0.0 names beside the old ones and flags in your editor each name, option and constant 3.0.0 removes. Then change the package name to `material` and follow the [3.0.0 migration guide](https://github.com/floor/material/blob/main/CHANGELOG.md#migrating-from-010x): `material` is ESM-only, the package root keeps the components (the internals move to their subpaths), "text field" is two words in every identifier, and a few leftovers fail silently instead of at compile time, such as a chip's `{ text }`, which renders an empty chip.
411
-
412
- ## Upgrading from `mtrl` 0.9
413
-
414
- 0.10.0 adds the elements and framework components; for factory users, most apps need nothing. The changes to check are listed in the [0.10.0 changelog's migration section](https://github.com/floor/material/blob/main/CHANGELOG.md#migrating-from-09x): setters no longer emit `change`, the time picker's events pass `{ value }`, the `--mtrl-sys-color-*-rgb` properties are gone, disabled non-form roots use `aria-disabled`, cards are `article`s, and the text field's DOM gained a `__field` wrapper.
415
-
416
- ## Upgrading from `mtrl` 0.7
417
-
418
- 0.8.0 aligns the components with Material 3 expressive, and some of that changes the API or the styles:
419
-
420
- - `createSheet` is removed; use `createBottomSheet` or `createSideSheet`.
421
- - FAB and extended FAB: `variant: 'primary'`, `'secondary'` and `'tertiary'` are now the tone styles; the former look is `'primary-container'` (the default), `'secondary-container'` and `'tertiary-container'`.
422
- - Component custom properties are renamed to `--mtrl-<component>-<name>`, for example `--drawer-width` to `--mtrl-drawer-width` and `--item-offset` to `--mtrl-list-item-offset`.
423
- - `title-large` uses weight 400, as M3 specifies.
424
- - The slider draws with DOM and CSS; styles for `.mtrl-slider-canvas` no longer apply.
425
-
426
- The full list, with every renamed property, is in the [0.8.0 changelog](https://github.com/floor/material/blob/main/CHANGELOG.md#080---2026-09-15).
427
-
428
- ## Browser support
113
+ The package was published as `mtrl` up to 0.10.x, and its history before 3.0.0 was developed in `floor/mtrl`. The class prefix (`mtrl-`), the custom properties, the `m-` tags and the cascade layers keep their names.
429
114
 
430
- Current Chrome, Edge, Firefox and Safari. The spring motion uses CSS `linear()` easing (Safari 17.2 or later); older browsers render every component but skip those transitions. The elements use form-associated custom elements and the top layer (`popover` and `<dialog>`), both available in every current browser.
115
+ Versions of `material` up to 1.0.4 are an earlier, separate library (GPL-3), still installable with `npm install material@legacy`.
431
116
 
432
- ## Contributing
117
+ ## Links
433
118
 
434
- Contributions are welcome. [CONTRIBUTING.md](.github/CONTRIBUTING.md) covers the development setup, conventions and the distribution checks.
119
+ [Documentation](https://md3.io) · [Repository and full README](https://github.com/floor/material#readme) · [Changelog](https://github.com/floor/material/blob/main/CHANGELOG.md) · [Issues](https://github.com/floor/material/issues)
435
120
 
436
121
  ## License
437
122
 
438
- MIT, see [LICENSE](LICENSE).
123
+ MIT, see [LICENSE](https://github.com/floor/material/blob/main/LICENSE).
@@ -4,5 +4,5 @@
4
4
  * @description A small element that communicates status, shows a count,
5
5
  * or highlights an element requiring attention.
6
6
  */
7
- export { default } from "./badge.js";
7
+ export { default, default as createBadge } from "./badge.js";
8
8
  export type { BadgeConfig, BadgeComponent, BadgeVariant, BadgeColor, BadgePosition, } from "./types.js";
@@ -1 +1 @@
1
- export { default } from "./badge.js";
1
+ export { default, default as createBadge } from "./badge.js";
@@ -2,7 +2,7 @@
2
2
  * Button component module
3
3
  * @module components/button
4
4
  */
5
- export { default } from "./button.js";
5
+ export { default, default as createButton } from "./button.js";
6
6
  export type { ButtonConfig, ButtonComponent, ButtonVariant, ButtonChangePayload } from "./types.js";
7
7
  export type { ButtonEvents } from "./types.js";
8
8
  export type { ButtonSize, ButtonShape } from "./constants.js";
@@ -1 +1 @@
1
- export { default } from "./button.js";
1
+ export { default, default as createButton } from "./button.js";
@@ -59,7 +59,7 @@
59
59
  * Factory function to create a new Card component.
60
60
  * @see CardComponent for the full API reference
61
61
  */
62
- export { default } from "./card.js";
62
+ export { default, default as createCard } from "./card.js";
63
63
  /**
64
64
  * Card component types and interfaces
65
65
  *
@@ -1,2 +1,2 @@
1
- export { default } from "./card.js";
1
+ export { default, default as createCard } from "./card.js";
2
2
  export { createCardContent, createCardHeader, createCardActions, createCardMedia, } from "./content.js";
@@ -7,7 +7,7 @@
7
7
  * @module components/checkbox
8
8
  * @category Components
9
9
  */
10
- export { default } from "./checkbox.js";
10
+ export { default, default as createCheckbox } from "./checkbox.js";
11
11
  export type { CheckboxConfig, CheckboxComponent, CheckboxEvents, CheckboxChangePayload, CheckboxLabelPosition } from "./types.js";
12
12
  /**
13
13
  * Constants for checkbox configuration
@@ -1,2 +1,2 @@
1
- export { default } from "./checkbox.js";
1
+ export { default, default as createCheckbox } from "./checkbox.js";
2
2
  export { CHECKBOX_LABEL_POSITION, CHECKBOX_STATES, CHECKBOX_CLASSES } from "./constants.js";
@@ -1,3 +1,3 @@
1
1
  export { createAssistChip, createFilterChip, createInputChip, createSuggestionChip } from "./factories.js";
2
- export { default as createChips } from "./chips.js";
2
+ export { default, default as createChips } from "./chips.js";
3
3
  export type { ChipConfig, ChipComponent, ChipType, ChipEvents, ChipChangePayload, AssistChipConfig, FilterChipConfig, InputChipConfig, SuggestionChipConfig, ChipsConfig, ChipsComponent, ChipsEvents, ChipsChangeEvent, ChipsAddEvent, ChipsRemoveEvent, } from "./types.js";
@@ -1,2 +1,2 @@
1
1
  export { createAssistChip, createFilterChip, createInputChip, createSuggestionChip } from "./factories.js";
2
- export { default as createChips } from "./chips.js";
2
+ export { default, default as createChips } from "./chips.js";
@@ -1,2 +1,2 @@
1
- export { default } from "./datepicker.js";
1
+ export { default, default as createDatePicker } from "./datepicker.js";
2
2
  export type { DatePickerConfig, DatePickerComponent, DatePickerEvents, DatePickerValue, DatePickerValueOf, DatePickerInput, DatePickerChangePayload, DatePickerVisibilityPayload, DatePickerTapPayload, DatePickerSwipePayload, DatePickerVariant, DatePickerView, DatePickerSelectionMode, CalendarAPI, } from "./types.js";
@@ -1 +1 @@
1
- export { default } from "./datepicker.js";
1
+ export { default, default as createDatePicker } from "./datepicker.js";
@@ -10,5 +10,5 @@
10
10
  * @module components/dialog
11
11
  * @category Components
12
12
  */
13
- export { default } from "./dialog.js";
13
+ export { default, default as createDialog } from "./dialog.js";
14
14
  export type { DialogConfig, DialogComponent, DialogButton, DialogEvent, DialogConfirmOptions, DialogSize, DialogAnimation, DialogFooterAlignment, DialogEventType, } from "./types.js";
@@ -1 +1 @@
1
- export { default } from "./dialog.js";
1
+ export { default, default as createDialog } from "./dialog.js";
@@ -28,6 +28,6 @@
28
28
  * @category Components
29
29
  */
30
30
  import { createDivider } from "./divider.js";
31
- export { createDivider };
31
+ export { createDivider, createDivider as default };
32
32
  export type { DividerConfig } from "./config.js";
33
33
  export type { DividerComponent } from "./types.js";