material-inspired-component-library 9.1.1 → 9.1.2

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 (61) hide show
  1. package/components/appbar/index.scss +1 -1
  2. package/components/badge/README.md +43 -12
  3. package/components/badge/index.scss +15 -21
  4. package/components/bottomsheet/README.md +53 -22
  5. package/components/bottomsheet/index.scss +61 -44
  6. package/components/button/_shared.scss +6 -6
  7. package/components/card/README.md +1 -1
  8. package/components/checkbox/index.scss +10 -10
  9. package/components/datepicker/README.md +184 -59
  10. package/components/datepicker/index.scss +84 -20
  11. package/components/dialog/README.md +151 -56
  12. package/components/dialog/index.scss +50 -62
  13. package/components/iconbutton/index.scss +5 -5
  14. package/components/list/index.scss +6 -6
  15. package/components/menu/index.scss +13 -13
  16. package/components/navigationbar/index.scss +7 -1
  17. package/components/navigationrail/index.scss +27 -22
  18. package/components/radio/index.scss +8 -8
  19. package/components/select/index.scss +3 -3
  20. package/components/sidesheet/README.md +90 -37
  21. package/components/sidesheet/index.scss +51 -41
  22. package/components/slider/README.md +35 -9
  23. package/components/slider/index.scss +182 -153
  24. package/components/snackbar/README.md +43 -25
  25. package/components/snackbar/index.scss +22 -27
  26. package/components/stepper/index.scss +4 -4
  27. package/components/switch/index.scss +13 -13
  28. package/components/timepicker/README.md +131 -55
  29. package/components/timepicker/index.scss +46 -25
  30. package/dist/appbar.css +1 -1
  31. package/dist/badge.css +1 -1
  32. package/dist/bottomsheet.css +1 -1
  33. package/dist/bottomsheet.js +1 -1
  34. package/dist/button.css +1 -1
  35. package/dist/checkbox.css +1 -1
  36. package/dist/chip.css +1 -1
  37. package/dist/datepicker.css +1 -1
  38. package/dist/datepicker.js +1 -1
  39. package/dist/dialog.css +1 -1
  40. package/dist/iconbutton.css +1 -1
  41. package/dist/layout.css +1 -1
  42. package/dist/list.css +1 -1
  43. package/dist/menu.css +1 -1
  44. package/dist/micl.css +1 -1
  45. package/dist/micl.js +1 -1
  46. package/dist/navigationbar.css +1 -1
  47. package/dist/navigationrail.css +1 -1
  48. package/dist/radio.css +1 -1
  49. package/dist/select.css +1 -1
  50. package/dist/sidesheet.css +1 -1
  51. package/dist/slider.css +1 -1
  52. package/dist/slider.js +1 -1
  53. package/dist/snackbar.css +1 -1
  54. package/dist/snackbar.js +1 -1
  55. package/dist/stepper.css +1 -1
  56. package/dist/switch.css +1 -1
  57. package/dist/timepicker.css +1 -1
  58. package/dist/timepicker.js +1 -1
  59. package/foundations/layout/_tokens.scss +55 -0
  60. package/foundations/layout/index.scss +2 -35
  61. package/package.json +1 -1
@@ -19,7 +19,7 @@
19
19
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
20
  // SOFTWARE.
21
21
 
22
- @use '../../foundations/layout';
22
+ @use '../../foundations/layout/tokens' as layout;
23
23
  @use '../../styles/elevation';
24
24
  @use '../../styles/motion';
25
25
  @use '../../styles/shape';
@@ -31,17 +31,16 @@
31
31
  @include shape.corner('extra-small');
32
32
 
33
33
  @include statelayer.token('hover-state-layer-opacity');
34
- @include statelayer.token('focus-state-layer-opacity');
35
34
  @include statelayer.token('pressed-state-layer-opacity');
36
35
  @include statelayer.property;
37
36
 
38
37
  @include typography.scale('body-medium');
39
38
 
40
39
  .micl-snackbar {
41
- --md-comp-snackbar-motion-spatial: #{motion.$md-sys-motion-expressive-default-spatial};
42
- --md-comp-snackbar-motion-duration: #{motion.$md-sys-motion-expressive-default-spatial-duration};
43
- --md-comp-snackbar-motion-duration-reverse: #{motion.$md-sys-motion-expressive-fast-spatial-duration};
44
- --micl-duration: var(--md-comp-snackbar-motion-duration-reverse);
40
+ --_motion-spatial: var(--md-comp-snackbar-motion-spatial, #{motion.$md-sys-motion-expressive-default-spatial});
41
+ --_motion-duration: var(--md-comp-snackbar-motion-duration, #{motion.$md-sys-motion-expressive-default-spatial-duration});
42
+ --_motion-duration-reverse: var(--md-comp-snackbar-motion-duration-reverse, #{motion.$md-sys-motion-expressive-fast-spatial-duration});
43
+ --micl-duration: var(--_motion-duration-reverse);
45
44
  --statelayer-color: var(--md-sys-color-inverse-primary);
46
45
  --statelayer-opacity: 0%;
47
46
 
@@ -53,13 +52,13 @@
53
52
  column-gap: 4px;
54
53
 
55
54
  block-size: 0;
56
- inline-size: max-content;
57
- max-inline-size: min(layout.$md-sys-breakpoint-expanded-max, calc(100vw - (2 * var(--md-sys-layout-window-margin))));
58
- min-inline-size: 300px;
55
+ inline-size: fit-content;
56
+ max-inline-size: var(--md-comp-snackbar-container-max-width, #{layout.$md-sys-breakpoint-medium-min});
57
+ min-inline-size: var(--md-comp-snackbar-container-min-width, 320px);
59
58
 
60
59
  inset: auto;
61
- inset-block-end: calc(var(--md-comp-snackbar-margin, 24px) + env(safe-area-inset-bottom));
62
- inset-inline: 0;
60
+ inset-block-end: calc(var(--md-comp-snackbar-margin, 8px) + env(safe-area-inset-bottom, 0px));
61
+ inset-inline: var(--md-sys-layout-window-margin);
63
62
  margin-block: 0;
64
63
  margin-inline: auto;
65
64
  padding-block: 0;
@@ -76,30 +75,26 @@
76
75
  background-size: 100%;
77
76
 
78
77
  opacity: 0;
79
- overflow-y: hidden;
78
+ overflow: clip;
80
79
 
81
80
  transition:
82
- block-size var(--micl-duration) var(--md-comp-snackbar-motion-spatial),
83
- opacity var(--md-comp-snackbar-motion-duration-reverse) linear,
84
- display var(--md-comp-snackbar-motion-duration-reverse) linear allow-discrete,
85
- overlay var(--md-comp-snackbar-motion-duration-reverse) linear allow-discrete,
86
- --statelayer-opacity var(--md-comp-snackbar-motion-duration) linear;
81
+ block-size var(--micl-duration) var(--_motion-spatial),
82
+ opacity var(--_motion-duration-reverse) linear,
83
+ display var(--_motion-duration-reverse) linear allow-discrete,
84
+ overlay var(--_motion-duration-reverse) linear allow-discrete,
85
+ --statelayer-opacity var(--_motion-duration) linear;
87
86
 
88
87
  &:hover {
89
- --statelayer-color: var(--md-comp-snackbar-action-hover-state-layer-color, var(--md-sys-color-inverse-primary));
90
- --statelayer-opacity: var(--md-comp-snackbar-action-hover-state-layer-opacity, var(--md-sys-state-hover-state-layer-opacity));
91
- }
92
- &:focus-visible {
93
- --statelayer-color: var(--md-comp-snackbar-action-focus-state-layer-color, var(--md-sys-color-inverse-primary));
94
- --statelayer-opacity: var(--md-comp-snackbar-action-focus-state-layer-opacity, var(--md-sys-state-focus-state-layer-opacity));
88
+ --statelayer-color: var(--md-comp-snackbar-hover-state-layer-color, var(--md-sys-color-inverse-primary));
89
+ --statelayer-opacity: var(--md-comp-snackbar-hover-state-layer-opacity, var(--md-sys-state-hover-state-layer-opacity));
95
90
  }
96
91
  &:active {
97
- --statelayer-color: var(--md-comp-snackbar-action-pressed-state-layer-color, var(--md-sys-color-inverse-primary));
98
- --statelayer-opacity: var(--md-comp-snackbar-action-pressed-state-layer-opacity, var(--md-sys-state-pressed-state-layer-opacity));
92
+ --statelayer-color: var(--md-comp-snackbar-pressed-state-layer-color, var(--md-sys-color-inverse-primary));
93
+ --statelayer-opacity: var(--md-comp-snackbar-pressed-state-layer-opacity, var(--md-sys-state-pressed-state-layer-opacity));
99
94
  }
100
95
 
101
96
  &:popover-open {
102
- --micl-duration: var(--md-comp-snackbar-motion-duration);
97
+ --micl-duration: var(--_motion-duration);
103
98
 
104
99
  block-size: var(--md-comp-snackbar-with-single-line-container-height, 48px);
105
100
  opacity: 1;
@@ -157,7 +152,7 @@
157
152
 
158
153
  @media (max-width: layout.$md-sys-breakpoint-compact-max) {
159
154
  .micl-snackbar {
160
- inline-size: calc(100vw - (2 * var(--md-sys-layout-window-margin)));
155
+ inline-size: auto;
161
156
  min-inline-size: auto;
162
157
  }
163
158
  }
@@ -25,8 +25,8 @@
25
25
  @include statelayer.token('disabled-state-layer-opacity');
26
26
 
27
27
  .micl-stepper {
28
- --md-comp-stepper-motion-spatial: #{motion.$md-sys-motion-expressive-slow-spatial};
29
- --md-comp-stepper-motion-duration: #{motion.$md-sys-motion-expressive-slow-spatial-duration};
28
+ --_motion-spatial: var(--md-comp-stepper-motion-spatial, #{motion.$md-sys-motion-expressive-slow-spatial});
29
+ --_motion-duration: var(--md-comp-stepper-motion-duration, #{motion.$md-sys-motion-expressive-slow-spatial-duration});
30
30
 
31
31
  --_dot-size: var(--md-comp-stepper-dot-size, 12px);
32
32
 
@@ -105,8 +105,8 @@
105
105
  opacity: 0%;
106
106
  transform: translateX(100%);
107
107
  transition:
108
- opacity var(--md-comp-stepper-motion-duration) linear,
109
- transform var(--md-comp-stepper-motion-duration) var(--md-comp-stepper-motion-spatial);
108
+ opacity var(--_motion-duration) linear,
109
+ transform var(--_motion-duration) var(--_motion-spatial);
110
110
 
111
111
  &:has(~ .micl-stepper__step[aria-current=step]) {
112
112
  transform: translateX(-100%);
@@ -37,10 +37,10 @@
37
37
  $switch: 'input[type=checkbox].micl-switch';
38
38
 
39
39
  #{$switch} {
40
- --md-comp-switch-unselected-icon: "+";
41
- --md-comp-switch-selected-icon: "\AC";
42
- --md-comp-switch-motion-effects: #{motion.$md-sys-motion-expressive-slow-effects};
43
- --md-comp-switch-motion-duration: #{motion.$md-sys-motion-expressive-slow-effects-duration};
40
+ --_unselected-icon: var(--md-comp-switch-unselected-icon, "+");
41
+ --_selected-icon: var(--md-comp-switch-selected-icon, "\AC");
42
+ --_motion-effects: var(--md-comp-switch-motion-effects, #{motion.$md-sys-motion-expressive-slow-effects});
43
+ --_motion-duration: var(--md-comp-switch-motion-duration, #{motion.$md-sys-motion-expressive-slow-effects-duration});
44
44
 
45
45
  --_track-width: var(--md-comp-switch-track-width, 52px);
46
46
  --_track-height: var(--md-comp-switch-track-height, 32px);
@@ -73,10 +73,10 @@ $switch: 'input[type=checkbox].micl-switch';
73
73
  border: var(--_track-outline-width) solid var(--md-comp-switch-unselected-track-outline-color, var(--md-sys-color-outline));
74
74
  border-radius: inherit;
75
75
  background-color: var(--md-comp-switch-unselected-track-color, var(--md-sys-color-surface-container-highest));
76
- transition: background-color var(--md-comp-switch-motion-duration) motion.$md-sys-motion-easing-emphasized;
76
+ transition: background-color var(--_motion-duration) motion.$md-sys-motion-easing-emphasized;
77
77
  }
78
78
  &::after {
79
- content: var(--md-comp-switch-unselected-icon);
79
+ content: var(--_unselected-icon);
80
80
  box-sizing: border-box;
81
81
  position: absolute;
82
82
  display: grid;
@@ -95,12 +95,12 @@ $switch: 'input[type=checkbox].micl-switch';
95
95
  border-radius: var(--md-sys-shape-corner-full);
96
96
  transform: rotate(135deg);
97
97
  transition:
98
- inset-inline-start var(--md-comp-switch-motion-duration) var(--md-comp-switch-motion-effects),
99
- border-width var(--md-comp-switch-motion-duration) var(--md-comp-switch-motion-effects),
100
- grid-template-rows var(--md-comp-switch-motion-duration) var(--md-comp-switch-motion-effects),
101
- color var(--md-comp-switch-motion-duration) motion.$md-sys-motion-easing-emphasized,
102
- border-color var(--md-comp-switch-motion-duration) motion.$md-sys-motion-easing-emphasized,
103
- background-color var(--md-comp-switch-motion-duration) motion.$md-sys-motion-easing-emphasized;
98
+ inset-inline-start var(--_motion-duration) var(--_motion-effects),
99
+ border-width var(--_motion-duration) var(--_motion-effects),
100
+ grid-template-rows var(--_motion-duration) var(--_motion-effects),
101
+ color var(--_motion-duration) motion.$md-sys-motion-easing-emphasized,
102
+ border-color var(--_motion-duration) motion.$md-sys-motion-easing-emphasized,
103
+ background-color var(--_motion-duration) motion.$md-sys-motion-easing-emphasized;
104
104
  }
105
105
  &:checked {
106
106
  &::before {
@@ -108,7 +108,7 @@ $switch: 'input[type=checkbox].micl-switch';
108
108
  background-color: var(--md-comp-switch-selected-track-color, var(--md-sys-color-primary));
109
109
  }
110
110
  &::after {
111
- content: var(--md-comp-switch-selected-icon);
111
+ content: var(--_selected-icon);
112
112
  grid-template-rows: auto 8px;
113
113
  inset-inline-start: calc(var(--_track-width) - ((var(--_layer) + var(--_track-height)) / 2));
114
114
  font-size: 32px;
@@ -1,22 +1,31 @@
1
1
  # Time picker
2
+
2
3
  This component implements the [Material Design 3 Expressive Time picker](https://m3.material.io/components/time-pickers/overview) design. It allows users to select a specific time of day using either a text input or an analog dial interface.
3
4
 
4
5
  ## Basic Usage
5
6
 
6
7
  ### HTML
7
- The Time picker component is an extension of the [**Dialog** component](../dialog/README.md). To create a basic time picker, use a `<dialog>` element with both `micl-dialog` and `micl-timepicker` classes.
8
+
9
+ The Time picker component is an extension of the [**Dialog** component](../dialog/README.md). To create a basic time picker, use a `<dialog>` element with both the `micl-dialog` and `micl-timepicker` classes.
8
10
 
9
11
  ```HTML
10
- <dialog id="mytimepicker" class="micl-dialog micl-timepicker" closedby="closerequest" aria-labelledby="mytitle">
12
+ <dialog
13
+ id="mytimepicker"
14
+ class="micl-dialog micl-timepicker"
15
+ closedby="closerequest"
16
+ aria-labelledby="mytitle"
17
+ data-micldialheadline="Select time"
18
+ data-miclinputheadline="Enter time"
19
+ >
11
20
  <form method="dialog">
12
21
  <div class="micl-dialog__headline">
13
- <h2 id="mytitle">Enter time</h2>
22
+ <h2 id="mytitle">Select time</h2>
14
23
  </div>
15
24
 
16
25
  <div class="micl-dialog__content">
17
- <input type="number" name="hour" value="00" aria-labelledby="myhour">
26
+ <input type="text" name="hour" value="00" aria-labelledby="myhour">
18
27
  <span class="micl-timepicker__separator">:</span>
19
- <input type="number" name="minute" value="00" aria-labelledby="myminute">
28
+ <input type="text" name="minute" value="00" aria-labelledby="myminute">
20
29
  <div class="micl-timepicker__period"></div>
21
30
  <span id="myhour" class="micl-timepicker__supporting-text-hour">Hour</span>
22
31
  <span id="myminute" class="micl-timepicker__supporting-text-minute">Minute</span>
@@ -42,124 +51,191 @@ The Time picker component is an extension of the [**Dialog** component](../dialo
42
51
  </div>
43
52
  </form>
44
53
  </dialog>
54
+
45
55
  ```
46
56
 
47
57
  ### CSS
48
- Import the time picker, dialog and button styles into your project:
58
+
59
+ Import the time picker, dialog, and button styles into your project:
49
60
 
50
61
  ```CSS
51
62
  @use "material-inspired-component-library/dist/dialog";
52
63
  @use "material-inspired-component-library/dist/button";
53
64
  @use "material-inspired-component-library/dist/iconbutton";
54
65
  @use "material-inspired-component-library/dist/timepicker";
66
+
55
67
  ```
56
68
 
57
69
  Or import all MICL styles:
70
+
58
71
  ```CSS
59
72
  @use "material-inspired-component-library/styles";
73
+
60
74
  ```
61
75
 
62
76
  ### JavaScript
77
+
63
78
  This component requires JavaScript to function:
64
79
 
65
80
  ```JavaScript
66
81
  import micl from "material-inspired-component-library/dist/micl";
82
+
67
83
  ```
68
- When loading individual JavaScript files, also load `dist/textfield` — it wires the input field that opens the picker.
69
84
 
70
85
  This will initialize any Time picker component, including those that will be added to the DOM later on.
71
86
 
87
+ If you are loading individual JavaScript modules, ensure you include `dist/textfield` (to wire the triggering input field) and `dist/button` (to manage the `aria-pressed` state and icon of the mode toggle).
88
+
72
89
  ### Live Demo
73
- A live example of the [Time picker component](https://henkpb.github.io/micl/timepicker.html) is available to interact with.
74
90
 
75
- ## Variants
76
- Because the Time picker component relies on the Dialog component, it utilizes the same utility classes for content structure. Refer to the [Dialog component documentation](../dialog/README.md) for structural details.
91
+ A live example of the [Time picker component](https://henkpb.github.io/micl/timepicker.html) is available for interaction.
92
+
93
+ ## Anatomy
94
+
95
+ As an extension of the Dialog component, the Time picker utilizes the same utility classes for its content structure. Refer to the [Dialog component documentation](../dialog/README.md) for base layout details.
77
96
 
78
- ### Time Picker Structure
79
97
  For the picker to function correctly, the `micl-dialog__content` area must contain:
80
98
 
81
- - Hour input: `<input type="number" name="hour">`
82
- - Minute input: `<input type="number" name="minute">`
83
- - Separator: A text element with class `micl-timepicker__separator` (e.g., a colon).
84
- - AM/PM Container: An empty `<div>` with class `micl-timepicker__period`. The component logic will populate this selector if the user's locale uses a 12-hour format.
85
- - Dial Container: An optional empty `<div>` with class `micl-timepicker__dial` for the analog clock interface.
86
- - Optional elements for "Hour" and "Minute" supporting text.
99
+ * **Hour input:** `<input type="text" name="hour">`
100
+ * **Minute input:** `<input type="text" name="minute">`
101
+ * **Separator:** A text element with the class `micl-timepicker__separator` (e.g., a colon).
102
+ * **AM/PM Container:** An empty `<div>` with the class `micl-timepicker__period`. The component logic populates this container automatically when using a 12-hour clock.
103
+ * **Dial Container:** An optional empty `<div>` with the class `micl-timepicker__dial` for the analog clock interface.
104
+ * **Supporting Text:** Optional elements mapping to "Hour" and "Minute" labels.
87
105
 
88
- By default, the layout is **vertical**. To switch to a **horizontal** layout (side-by-side inputs and dial), add the modifier class `micl-timepicker--horizontal` to the `<dialog>`.
106
+ By default, the layout is **vertical**. To switch to a **horizontal** layout (side-by-side inputs and dial), add the `micl-timepicker--horizontal` modifier class to the `<dialog>`. The two layouts only differ visually while the dial is displayed.
89
107
 
90
- #### Input Mode Switching
91
- To allow users to toggle between the text inputs and the analog dial, add an icon [toggle button](../button/README.md#toggle-button) to the `micl-dialog__actions` container, as shown in the basic example above:
108
+ ## Variants
109
+
110
+ #### 12-Hour and 24-Hour Clocks
111
+
112
+ By default, the picker adopts the hour cycle of the user's locale: a 12-hour clock displays an AM/PM selector and hours 1–12 on the dial, while a 24-hour clock displays hours 0–11 on the outer ring and 12–23 on the inner ring. The AM/PM labels reflect the locale's day period names (e.g., a Spanish locale will display *a.m.* / *p.m.*).
113
+
114
+ To explicitly set the clock format regardless of the user's locale (useful for applications with custom locale switchers), add `data-miclhourcycle` to the `<dialog>`:
115
+
116
+ ```HTML
117
+ <dialog class="micl-dialog micl-timepicker" data-miclhourcycle="h12" closedby="closerequest">
118
+ ...
119
+ </dialog>
92
120
 
93
- - Class: `micl-timepicker__inputmode` in addition to the icon button and `micl-button--toggle` classes.
94
- - A self-targeting `commandfor`/`command="--micl-toggle"` pair, which flips the button's `aria-pressed` state on activation.
95
- - Data Attribute: `data-miclicon="keyboard"` (the icon shown in dial mode, when `aria-pressed="false"`).
96
- - Data Attribute: `data-micliconselected="schedule"` (the icon shown in input mode, when `aria-pressed="true"`).
121
+ ```
122
+
123
+ Accepted values are `h11` and `h12` (for 12-hour formatting) and `h23` and `h24` (for 24-hour formatting). These map directly to the [`hourCycle`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/resolvedOptions) values reported by `Intl`.
97
124
 
98
125
  #### Starting in Input Mode
99
- The picker opens in dial mode by default. To open it in input mode instead, add the `micl-timepicker__dial--hidden` class to the `micl-timepicker__dial` element, and set `aria-pressed="true"` on the `micl-timepicker__inputmode` button so it shows the matching `schedule` icon. The two attributes are independent, so they must agree in the initial markup.
126
+
127
+ By default, the picker opens in dial mode. To default to input mode, add the `micl-timepicker__dial--hidden` class to the `micl-timepicker__dial` element, and set `aria-pressed="true"` on the `micl-timepicker__inputmode` button so it displays the matching `schedule` icon. These two attributes operate independently and must be synced in your initial markup.
128
+
129
+ #### Input Mode Switching
130
+
131
+ To allow users to toggle between text inputs and the analog dial, add an icon [toggle button](../iconbutton/README.md) to the `micl-dialog__actions` container, as shown in the basic example:
132
+
133
+ * **Class:** `micl-timepicker__inputmode` alongside the standard icon button and `micl-button--toggle` classes.
134
+ * **Behavior:** A self-targeting `commandfor` / `command="--micl-toggle"` pair flips the button's `aria-pressed` state upon activation.
135
+ * **Dial Icon:** `data-miclicon="keyboard"` (displayed in dial mode when `aria-pressed="false"`).
136
+ * **Input Icon:** `data-micliconselected="schedule"` (displayed in input mode when `aria-pressed="true"`).
137
+
138
+ Material Design specifies different headlines for the two modes. By adding `data-micldialheadline` and `data-miclinputheadline` to the `<dialog>`, the component will dynamically update the headline text to match the current mode. If omitted, the default heading remains static.
100
139
 
101
140
  ### Integration
141
+
102
142
  You can trigger the Time picker component from standard input fields or buttons.
103
143
 
104
144
  #### Connecting to an Input Field
105
- To replace the browser's native time picker, add the `data-timepicker` attribute to an `<input>` element. The value of this attribute must match the `id` of your Time picker dialog.
145
+
146
+ To replace the browser's native time picker, assign the `data-timepicker` attribute to an `<input>` element. The value of this attribute must match the `id` of your Time picker dialog.
106
147
 
107
148
  ```HTML
108
149
  <input type="time" data-timepicker="mytimepicker" value="09:41">
150
+
109
151
  ```
110
152
 
111
- - **Behavior**: Clicking the input opens the picker initialized with the input's current value.
112
- - **Reusability**: Multiple input fields can target the same Time picker component ID. The picker will automatically update to reflect the time of the specific input field engaged by the user.
153
+ * **Behavior**: Clicking the input opens the picker, initialized to the input's current value.
154
+ * **Reusability**: Multiple input fields can target the same Time picker ID. The component will automatically read from and write to the specific input field the user interacted with.
113
155
 
114
156
  #### Connecting to a Button
115
- You can trigger the picker from a button using the standard `popovertarget` attribute.
157
+
158
+ You can trigger the picker from a button using standard `command` / `commandfor` attributes.
116
159
 
117
160
  ```HTML
118
- <button type="button" class="micl-button-text-m" popovertarget="mytimepicker" value="09:41">09:41</button>
161
+ <button
162
+ type="button"
163
+ class="micl-button-text-m"
164
+ command="show-modal"
165
+ commandfor="mytimepicker"
166
+ value="09:41"
167
+ >09:41</button>
168
+
119
169
  ```
120
170
 
121
- - **Behavior**: The Time picker reads from and writes to the button's value attribute.
122
- - **Formatting**: The component automatically updates the button's text content with the selected time, formatted according to the user's locale.
171
+ * **Behavior**: The Time picker reads from and writes to the button's `value` attribute, which must hold the time in 24-hour `HH:MM` format.
172
+ * **Formatting**: The component updates the button's visible text content with the selected time, formatted according to the user's locale.
173
+
174
+ > [!NOTE]
175
+ > Because a time picker requires explicit user confirmation, it must function as a modal dialog. Opening it as a popover (`popovertarget`) is **not supported**. A `<dialog popover>` does not fire the standard `close` event required by the component to write the selected time back to the invoker.
176
+
177
+ ## Accessibility
178
+
179
+ * **Always label the dialog.** Point `aria-labelledby` to the headline element. Additionally, ensure both input fields use `aria-labelledby` to point to their respective supporting text elements (as demonstrated in the HTML snippet).
180
+ * **Ensure full keyboard navigation.** The two input fields serve as the primary keyboard path. Exposed as spin buttons, they respond to <kbd>↑</kbd> and <kbd>↓</kbd> keys in *both* modes, wrapping at the limits of their ranges. On a 12-hour clock, wrapping past 12 or below 1 automatically toggles the AM/PM selector.
181
+ * **Hide the dial from assistive technologies.** The dial is purely a pointer affordance. It uses `aria-hidden="true"` to prevent screen readers from announcing an inoperable list of numbers. Everything configurable via the dial is fully accessible via the input fields.
182
+ * **Manage field states dynamically.** The input fields are marked `read-only` while in dial mode to prevent mobile on-screen keyboards from appearing unnecessarily. Switching to input mode restores editability, moves focus to the hour field, and selects its contents.
183
+ * **Provide context for the toggle button.** The mode toggle is an icon-only button; it requires an `aria-label`. Its `aria-pressed` state programmatically communicates the active mode to screen readers.
184
+ * **Respect motion preferences.** The selector visually sweeps between values only if the user has not enabled OS-level reduced motion.
123
185
 
124
186
  ## Theming
125
- Each time picker can be themed with CSS custom properties that follow the Material Design 3 component-token naming convention. The container color, shape and elevation are inherited from the [Dialog component](../dialog/README.md).
187
+
188
+ Time pickers can be themed using CSS custom properties adhering to the Material Design 3 component-token naming convention. Container color, shape, and elevation are inherited directly from the [Dialog component](../dialog/README.md).
126
189
 
127
190
  | Custom property | Meaning | Default |
128
- |---|---|---|
191
+ | --- | --- | --- |
192
+ | `--md-comp-time-picker-motion-duration` | Duration of the selector sweep and state layer fades | `--md-sys-motion-expressive-fast-spatial-duration` |
129
193
  | `--md-comp-time-picker-time-selector-container-height` | Height of the hour and minute input boxes | `72px` (`80px` in dial mode) |
130
194
  | `--md-comp-time-picker-time-selector-container-width` | Width of the input boxes in 12-hour mode | `96px` |
131
195
  | `--md-comp-time-picker-time-selector-24h-container-width` | Width of the input boxes in 24-hour mode | `114px` |
132
- | `--md-comp-time-picker-time-selector-unselected-container-color` | The background color of the input boxes | `--md-sys-color-surface-container-highest` |
133
- | `--md-comp-time-picker-time-selector-unselected-label-text-color` | The text color of the input boxes | `--md-sys-color-on-surface` |
134
- | `--md-comp-time-picker-time-selector-selected-container-color` | The background color of the active input box | `--md-sys-color-primary-container` |
135
- | `--md-comp-time-picker-time-selector-selected-label-text-color` | The text color of the active input box | `--md-sys-color-on-primary-container` |
136
- | `--md-comp-time-input-focus-outline-color` | The border color of the active input box in keyboard input mode | `--md-sys-color-primary` |
137
- | `--md-comp-time-picker-separator-width` | Width of the space containing the colon separator | `24px` |
138
- | `--md-comp-time-picker-separator-color` | The color of the colon separator | `--md-sys-color-on-surface` |
139
- | `--md-comp-time-picker-headline-color` | The text color of the headline | `--md-sys-color-on-surface-variant` |
140
- | `--md-comp-time-picker-supporting-text-color` | The text color of the labels below the input boxes | `--md-sys-color-on-surface-variant` |
196
+ | `--md-comp-time-picker-time-selector-unselected-container-color` | Background color of inactive input boxes | `--md-sys-color-surface-container-highest` |
197
+ | `--md-comp-time-picker-time-selector-unselected-label-text-color` | Text color of inactive input boxes | `--md-sys-color-on-surface` |
198
+ | `--md-comp-time-picker-time-selector-selected-container-color` | Background color of the active input box | `--md-sys-color-primary-container` |
199
+ | `--md-comp-time-picker-time-selector-selected-label-text-color` | Text color of the active input box | `--md-sys-color-on-primary-container` |
200
+ | `--md-comp-time-input-focus-outline-color` | Border color of the active input box in keyboard input mode | `--md-sys-color-primary` |
201
+ | `--md-comp-time-picker-separator-width` | Width of the container holding the colon separator | `24px` |
202
+ | `--md-comp-time-picker-separator-color` | Color of the colon separator | `--md-sys-color-on-surface` |
203
+ | `--md-comp-time-picker-headline-color` | Text color of the dialog headline | `--md-sys-color-on-surface-variant` |
204
+ | `--md-comp-time-picker-supporting-text-color` | Text color of the labels beneath the input boxes | `--md-sys-color-on-surface-variant` |
141
205
  | `--md-comp-time-picker-period-selector-container-height` | Total height of the AM/PM selector toggle | `72px` (`80px` or `38px` in dial modes) |
142
206
  | `--md-comp-time-picker-period-selector-container-width` | Width of the AM/PM selector toggle | `52px` |
143
- | `--md-comp-time-picker-period-selector-outline-color` | The border color of the AM/PM selector toggle | `--md-sys-color-outline` |
144
- | `--md-comp-time-picker-period-selector-unselected-label-text-color` | The text color of the unselected period | `--md-sys-color-on-surface-variant` |
145
- | `--md-comp-time-picker-period-selector-selected-container-color` | The background color of the selected period | `--md-sys-color-tertiary-container` |
146
- | `--md-comp-time-picker-period-selector-selected-label-text-color` | The text color of the selected period | `--md-sys-color-on-tertiary-container` |
207
+ | `--md-comp-time-picker-period-selector-outline-color` | Border color of the AM/PM selector toggle | `--md-sys-color-outline` |
208
+ | `--md-comp-time-picker-period-selector-unselected-label-text-color` | Text color of the unselected period | `--md-sys-color-on-surface-variant` |
209
+ | `--md-comp-time-picker-period-selector-selected-container-color` | Background color of the selected period | `--md-sys-color-tertiary-container` |
210
+ | `--md-comp-time-picker-period-selector-selected-label-text-color` | Text color of the selected period | `--md-sys-color-on-tertiary-container` |
147
211
  | `--md-comp-time-picker-clock-dial-container-size` | Diameter of the analog clock face | `256px` |
148
- | `--md-comp-time-picker-clock-dial-color` | The background color of the analog clock face | `--md-sys-color-surface-container-highest` |
149
- | `--md-comp-time-picker-clock-dial-unselected-label-text-color` | The text color of the dial marks | `--md-sys-color-on-surface` |
150
- | `--md-comp-time-picker-clock-dial-selected-label-text-color` | The text color of the selected dial mark | `--md-sys-color-on-primary` |
151
- | `--md-comp-time-picker-clock-dial-selector-handle-container-color` | The background color of the selected dial mark | `--md-sys-color-primary` |
152
- | `--md-comp-time-picker-clock-dial-selector-track-container-color` | The color of the selector track line on the dial | `--md-sys-color-primary` |
212
+ | `--md-comp-time-picker-clock-dial-color` | Background color of the analog clock face | `--md-sys-color-surface-container-highest` |
213
+ | `--md-comp-time-picker-clock-dial-unselected-label-text-color` | Text color of the unselected dial marks | `--md-sys-color-on-surface` |
214
+ | `--md-comp-time-picker-clock-dial-selected-label-text-color` | Text color of the selected dial mark | `--md-sys-color-on-primary` |
215
+ | `--md-comp-time-picker-clock-dial-selector-handle-container-color` | Background color of the selected dial mark | `--md-sys-color-primary` |
216
+ | `--md-comp-time-picker-clock-dial-selector-track-container-color` | Color of the selector track line on the dial | `--md-sys-color-primary` |
153
217
  | `--md-comp-time-picker-clock-dial-selector-track-container-width` | Thickness of the selector track line on the dial | `2px` |
154
- | `--md-comp-time-picker-clock-dial-selector-center-container-color` | The color of the center dot of the dial | `--md-sys-color-primary` |
155
- | `--md-comp-time-picker-clock-dial-selector-center-container-size` | Diameter of the center dot of the dial | `8px` |
218
+ | `--md-comp-time-picker-clock-dial-selector-center-container-color` | Color of the center dot on the dial | `--md-sys-color-primary` |
219
+ | `--md-comp-time-picker-clock-dial-selector-center-container-size` | Diameter of the center dot on the dial | `8px` |
156
220
 
157
221
  **Example: Changing the width of the dial track**
158
222
 
159
223
  ```HTML
160
- <div style="--md-comp-time-picker-clock-dial-selector-track-container-width:3px">
224
+ <div style="--md-comp-time-picker-clock-dial-selector-track-container-width: 3px;">
161
225
  <dialog class="micl-dialog micl-timepicker" closedby="closerequest">
162
226
  ...
163
227
  </dialog>
164
228
  </div>
229
+
165
230
  ```
231
+
232
+ ## Compatibility
233
+
234
+ This component relies on modern web platform features. Review *Browser compatibility* before deploying it in production environments.
235
+
236
+ * **Open/Close Mechanisms:** Relies on the `<dialog>` element's [`beforetoggle`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/beforetoggle_event) event to load the invoker's time, and on the `close` event to write it back. Buttons open the picker using the [Invoker Commands API](https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API) (`command` / `commandfor`). In browsers where this is unsupported, you must trigger `showModal()` manually.
237
+ * **Input Mode Toggle:** The icon and `aria-pressed` state of the toggle button are driven by a custom invoker command. Without Invoker Commands support, the dial will still toggle, but the button will not visually reflect the active mode.
238
+ * **Selector Sweep:** The animated dial selector utilizes a registered [`@property`](https://developer.mozilla.org/en-US/docs/Web/CSS/@property) custom property of type `<angle>`. In browsers without `@property` support, the selector will snap to the new value instantly rather than sweeping smoothly.
239
+ * **Dial Geometry:** The clock face calculates mark positions using the [`cos()` and `sin()](https://developer.mozilla.org/en-US/docs/Web/CSS/sin)` trigonometric CSS functions.
240
+ * **Advanced Styling:** Utilizes [`:has()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:has), [`:dir()`](https://developer.mozilla.org/en-US/docs/Web/CSS/:dir), and [relative color syntax](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_colors/Relative_colors) to handle layout switching, right-to-left rendering, and state layer opacities.
241
+ * **Locale Data:** Locale-specific details (hour cycle, AM/PM labels, button text formatting) are sourced from [`Intl.DateTimeFormat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). If the lookup fails, the component safely falls back to a 24-hour clock using English day periods.