@reliability-design/web 1.4.6 → 1.4.8

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 (148) hide show
  1. package/CHANGELOG.md +246 -49
  2. package/dist/components/rel-accordion/README.md +133 -132
  3. package/dist/components/rel-alert/README.md +145 -141
  4. package/dist/components/rel-autocomplete/README.md +172 -61
  5. package/dist/components/rel-avatar/README.md +118 -130
  6. package/dist/components/rel-badge/README.md +97 -93
  7. package/dist/components/rel-breadcrumb/README.md +96 -102
  8. package/dist/components/rel-button/README.md +190 -130
  9. package/dist/components/rel-calendar/README.md +109 -109
  10. package/dist/components/rel-card/README.md +75 -94
  11. package/dist/components/rel-cardmedia/README.md +100 -127
  12. package/dist/components/rel-carousel/README.md +186 -166
  13. package/dist/components/rel-checkbox/README.md +96 -75
  14. package/dist/components/rel-chip/README.md +138 -121
  15. package/dist/components/rel-container/README.md +107 -99
  16. package/dist/components/rel-date-picker/README.md +200 -289
  17. package/dist/components/rel-divider/README.md +88 -100
  18. package/dist/components/rel-drawer/README.md +187 -200
  19. package/dist/components/rel-kbd/README.md +141 -151
  20. package/dist/components/rel-layout/README.md +34 -0
  21. package/dist/components/rel-menu/README.md +180 -151
  22. package/dist/components/rel-menubar/README.md +218 -329
  23. package/dist/components/rel-otp/README.md +171 -440
  24. package/dist/components/rel-pagination/README.md +100 -424
  25. package/dist/components/rel-popover/README.md +203 -568
  26. package/dist/components/rel-progress/README.md +88 -110
  27. package/dist/components/rel-radio/README.md +131 -138
  28. package/dist/components/rel-range-picker/README.md +165 -0
  29. package/dist/components/rel-resizable/README.md +199 -140
  30. package/dist/components/rel-segmented-button/README.md +156 -141
  31. package/dist/components/rel-select/README.md +156 -93
  32. package/dist/components/rel-sheet/README.md +168 -224
  33. package/dist/components/rel-skeleton/README.md +104 -0
  34. package/dist/components/rel-slider/README.md +131 -135
  35. package/dist/components/rel-snackbar/README.md +168 -134
  36. package/dist/components/rel-stepper/README.md +162 -160
  37. package/dist/components/rel-switch/README.md +117 -102
  38. package/dist/components/rel-tab/README.md +173 -163
  39. package/dist/components/rel-textfield/README.md +176 -69
  40. package/dist/components/rel-time-picker/README.md +122 -157
  41. package/dist/components/rel-toast/README.md +165 -148
  42. package/dist/components/rel-tooltip/README.md +119 -111
  43. package/dist/components/rel-upload/README.md +220 -0
  44. package/dist/index.d.mts +1726 -447
  45. package/dist/index.d.ts +1726 -447
  46. package/dist/index.js +13715 -10870
  47. package/dist/index.js.map +1 -1
  48. package/dist/index.mjs +14018 -11163
  49. package/dist/index.mjs.map +1 -1
  50. package/dist/styles/focus-ring.ts +84 -0
  51. package/dist/styles/vars.css +892 -866
  52. package/dist/{vars-XNMTSRVN.css → vars-DXX6QOAG.css} +892 -866
  53. package/package.json +3 -2
  54. package/dist/components/rel-accordion/rel-accordion.ts +0 -336
  55. package/dist/components/rel-alert/rel-alert.ts +0 -305
  56. package/dist/components/rel-autocomplete/rel-autocomplete.ts +0 -720
  57. package/dist/components/rel-avatar/rel-avatar.ts +0 -142
  58. package/dist/components/rel-badge/rel-badge.ts +0 -175
  59. package/dist/components/rel-breadcrumb/rel-breadcrumb.ts +0 -106
  60. package/dist/components/rel-button/rel-button.ts +0 -560
  61. package/dist/components/rel-calendar/index.ts +0 -1
  62. package/dist/components/rel-calendar/rel-calendar.ts +0 -565
  63. package/dist/components/rel-card/rel-card.ts +0 -88
  64. package/dist/components/rel-cardmedia/rel-cardmedia.ts +0 -88
  65. package/dist/components/rel-carousel/index.ts +0 -1
  66. package/dist/components/rel-carousel/rel-carousel.ts +0 -723
  67. package/dist/components/rel-chart/README.md +0 -286
  68. package/dist/components/rel-chart/index.ts +0 -1
  69. package/dist/components/rel-chart/rel-chart.ts +0 -754
  70. package/dist/components/rel-checkbox/rel-checkbox.ts +0 -382
  71. package/dist/components/rel-chip/rel-chip.ts +0 -483
  72. package/dist/components/rel-container/rel-container.ts +0 -95
  73. package/dist/components/rel-date-picker/date-format.test.ts +0 -43
  74. package/dist/components/rel-date-picker/date-format.ts +0 -47
  75. package/dist/components/rel-date-picker/date-parse.test.ts +0 -116
  76. package/dist/components/rel-date-picker/date-parse.ts +0 -178
  77. package/dist/components/rel-date-picker/index.ts +0 -1
  78. package/dist/components/rel-date-picker/rel-date-picker.ts +0 -1676
  79. package/dist/components/rel-divider/rel-divider.ts +0 -54
  80. package/dist/components/rel-drawer/index.ts +0 -1
  81. package/dist/components/rel-drawer/rel-drawer-footer.ts +0 -27
  82. package/dist/components/rel-drawer/rel-drawer.ts +0 -607
  83. package/dist/components/rel-kbd/rel-kbd.ts +0 -188
  84. package/dist/components/rel-layout/rel-layout.ts +0 -49
  85. package/dist/components/rel-menu/rel-menu.ts +0 -541
  86. package/dist/components/rel-menubar/index.ts +0 -2
  87. package/dist/components/rel-menubar/rel-menubar-menu.css +0 -3
  88. package/dist/components/rel-menubar/rel-menubar-menu.ts +0 -17
  89. package/dist/components/rel-menubar/rel-menubar.ts +0 -777
  90. package/dist/components/rel-nav-menu/README.md +0 -289
  91. package/dist/components/rel-nav-menu/index.ts +0 -3
  92. package/dist/components/rel-nav-menu/rel-nav-menu-item.ts +0 -243
  93. package/dist/components/rel-nav-menu/rel-nav-menu-panel.ts +0 -72
  94. package/dist/components/rel-nav-menu/rel-nav-menu.ts +0 -270
  95. package/dist/components/rel-navbar/README.md +0 -126
  96. package/dist/components/rel-navbar/rel-navbar.ts +0 -105
  97. package/dist/components/rel-otp/index.ts +0 -1
  98. package/dist/components/rel-otp/rel-otp.ts +0 -527
  99. package/dist/components/rel-pagination/index.ts +0 -1
  100. package/dist/components/rel-pagination/rel-pagination.ts +0 -522
  101. package/dist/components/rel-popover/index.ts +0 -2
  102. package/dist/components/rel-popover/rel-popover-content.ts +0 -81
  103. package/dist/components/rel-popover/rel-popover.ts +0 -475
  104. package/dist/components/rel-progress/rel-progress.ts +0 -234
  105. package/dist/components/rel-radio/rel-radio.ts +0 -481
  106. package/dist/components/rel-range-picker/rel-range-picker.ts +0 -1688
  107. package/dist/components/rel-resizable/index.ts +0 -3
  108. package/dist/components/rel-resizable/rel-resizable-group.ts +0 -405
  109. package/dist/components/rel-resizable/rel-resizable-handle.ts +0 -150
  110. package/dist/components/rel-resizable/rel-resizable-panel.ts +0 -58
  111. package/dist/components/rel-segmented-button/rel-segmented-button.ts +0 -217
  112. package/dist/components/rel-select/rel-select.ts +0 -1416
  113. package/dist/components/rel-sheet/rel-sheet.ts +0 -610
  114. package/dist/components/rel-sidebar/README.md +0 -209
  115. package/dist/components/rel-sidebar/rel-sidebar.ts +0 -1191
  116. package/dist/components/rel-skeleton/rel-skeleton.ts +0 -143
  117. package/dist/components/rel-slider/rel-slider.ts +0 -673
  118. package/dist/components/rel-snackbar/rel-snackbar.ts +0 -329
  119. package/dist/components/rel-stepper/rel-stepper.ts +0 -567
  120. package/dist/components/rel-switch/rel-switch.ts +0 -199
  121. package/dist/components/rel-tab/rel-tab.ts +0 -264
  122. package/dist/components/rel-table/README.md +0 -178
  123. package/dist/components/rel-table/rel-table-body.ts +0 -22
  124. package/dist/components/rel-table/rel-table-caption.ts +0 -30
  125. package/dist/components/rel-table/rel-table-cell.ts +0 -43
  126. package/dist/components/rel-table/rel-table-footer.ts +0 -24
  127. package/dist/components/rel-table/rel-table-head.ts +0 -47
  128. package/dist/components/rel-table/rel-table-header.ts +0 -22
  129. package/dist/components/rel-table/rel-table-row.ts +0 -37
  130. package/dist/components/rel-table/rel-table.ts +0 -62
  131. package/dist/components/rel-textfield/rel-textfield.ts +0 -1054
  132. package/dist/components/rel-time-picker/rel-time-picker.ts +0 -1482
  133. package/dist/components/rel-time-picker/time-parse.test.ts +0 -67
  134. package/dist/components/rel-time-picker/time-parse.ts +0 -85
  135. package/dist/components/rel-toast/rel-toast.ts +0 -206
  136. package/dist/components/rel-tooltip/rel-tooltip.ts +0 -193
  137. package/dist/components/rel-topbar/rel-topbar-actions.ts +0 -27
  138. package/dist/components/rel-topbar/rel-topbar-brand.ts +0 -54
  139. package/dist/components/rel-topbar/rel-topbar-dropdown-item.ts +0 -69
  140. package/dist/components/rel-topbar/rel-topbar-dropdown.ts +0 -31
  141. package/dist/components/rel-topbar/rel-topbar-item.ts +0 -324
  142. package/dist/components/rel-topbar/rel-topbar-mobile-panel.ts +0 -27
  143. package/dist/components/rel-topbar/rel-topbar-profile.ts +0 -243
  144. package/dist/components/rel-topbar/rel-topbar-utilities.ts +0 -27
  145. package/dist/components/rel-topbar/rel-topbar.ts +0 -446
  146. package/dist/components/rel-upload/UPLOAD-DESIGN-CHANGES.md +0 -134
  147. package/dist/components/rel-upload/rel-upload-actions.ts +0 -163
  148. package/dist/components/rel-upload/rel-upload.ts +0 -968
@@ -1,289 +1,200 @@
1
- # rel-date-picker
2
-
3
- A fully accessible date picker component built with Lit for the Reliability Design System. Features a trigger button with calendar popover including month/year dropdowns.
4
-
5
- ## Features
6
-
7
- - Trigger button with calendar popover
8
- - Month and year dropdowns for easy navigation
9
- - Single date selection
10
- - Optional clear button
11
- - Min/max date constraints
12
- - Custom disabled date predicate
13
- - Keyboard navigation
14
- - Full ARIA support
15
- - Token-driven styling
16
-
17
- ## Usage
18
-
19
- ### Basic
20
-
21
- ```html
22
- <rel-date-picker></rel-date-picker>
23
- ```
24
-
25
- ### With Value
26
-
27
- ```html
28
- <rel-date-picker value="2026-01-16"></rel-date-picker>
29
- ```
30
-
31
- ### With Label
32
-
33
- ```html
34
- <rel-date-picker label="Select appointment date"></rel-date-picker>
35
- ```
36
-
37
- ### With Min/Max
38
-
39
- ```html
40
- <rel-date-picker
41
- min="2026-01-01"
42
- max="2026-12-31"
43
- placeholder="Select a date in 2026"
44
- ></rel-date-picker>
45
- ```
46
-
47
- ### Clearable
48
-
49
- ```html
50
- <rel-date-picker value="2026-01-16" clearable></rel-date-picker>
51
- ```
52
-
53
- ### Disabled
54
-
55
- ```html
56
- <rel-date-picker value="2026-01-16" disabled></rel-date-picker>
57
- ```
58
-
59
- ### Programmatic Control (JavaScript)
60
-
61
- ```javascript
62
- const picker = document.querySelector('rel-date-picker');
63
-
64
- // Set value
65
- picker.value = '2026-01-16';
66
-
67
- // Open programmatically
68
- picker.open = true;
69
-
70
- // Custom disabled dates (e.g., disable weekends)
71
- picker.isDateDisabled = (date) => {
72
- const day = date.getDay();
73
- return day === 0 || day === 6; // Sunday or Saturday
74
- };
75
-
76
- // Listen to changes
77
- picker.addEventListener('rel-change', (e) => {
78
- console.log('Selected date:', e.detail.value); // "2026-01-16"
79
- console.log('Date object:', e.detail.date); // Date object
80
- });
81
-
82
- // Listen to popover open/close
83
- picker.addEventListener('rel-open-change', (e) => {
84
- console.log('Popover open:', e.detail.open); // boolean
85
- });
86
- ```
87
-
88
- ## Attributes
89
-
90
- | Attribute | Type | Default | Description |
91
- |-----------|------|---------|-------------|
92
- | `value` | `string \| null` | `null` | Selected date in ISO format (YYYY-MM-DD) |
93
- | `placeholder` | `string` | `"Select date"` | Placeholder text when no date selected |
94
- | `label` | `string \| null` | `null` | Accessible label for the date picker |
95
- | `disabled` | `boolean` | `false` | Disables all interaction |
96
- | `required` | `boolean` | `false` | Sets aria-required (no validation logic) |
97
- | `min` | `string \| null` | `null` | Minimum selectable date (ISO format) |
98
- | `max` | `string \| null` | `null` | Maximum selectable date (ISO format) |
99
- | `week-start` | `"sun" \| "mon"` | `"sun"` | First day of the week |
100
- | `locale` | `string` | `"en-US"` | Locale for weekday labels and named-month display tokens (uses Intl.DateTimeFormat) |
101
- | `display-format` | `string \| null` | `null` | Token pattern for the selected value (see [Display format](#display-format)). Unset → locale long date |
102
- | `open` | `boolean` | `false` | Controls popover open state |
103
- | `close-on-select` | `boolean` | `true` | Close popover after selecting a date |
104
- | `clearable` | `boolean` | `false` | Show clear button when date is selected |
105
-
106
- ## Properties
107
-
108
- | Property | Type | Description |
109
- |----------|------|-------------|
110
- | `isDateDisabled` | `(date: Date) => boolean` | Custom function to disable specific dates |
111
- | `formatDate` | `(date: Date) => string` | Full control of the selected-value display; takes precedence over `display-format`. Set via property (not an attribute) |
112
-
113
- ## Display format
114
-
115
- By default the selected date is shown using the locale's long date (e.g. `July 21, 2026`). To render a fixed format instead, set `display-format` to a token pattern, or set the `formatDate` property to a callback for full control. Both affect **only the visible trigger text** — the underlying `value` stays ISO (`YYYY-MM-DD`), and parsing, the calendar, and accessibility are unchanged.
116
-
117
- ```html
118
- <rel-date-picker value="2026-07-21" display-format="YYYY-MM-DD"></rel-date-picker> <!-- 2026-07-21 -->
119
- <rel-date-picker value="2026-07-21" display-format="MM/DD/YYYY"></rel-date-picker> <!-- 07/21/2026 -->
120
- <rel-date-picker value="2026-07-21" display-format="DD/MM/YYYY"></rel-date-picker> <!-- 21/07/2026 -->
121
- <rel-date-picker value="2026-07-21" display-format="DD MMM YYYY"></rel-date-picker> <!-- 21 Jul 2026 -->
122
- ```
123
-
124
- ```js
125
- // Full control via callback (wins over display-format). Use it for logic a
126
- // pattern can't express — e.g. relative labels or fiscal periods.
127
- picker.formatDate = (date) => `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}`;
128
- ```
129
-
130
- > **Timezone note:** the `date` passed to `formatDate` is at **local midnight**. Read it with local getters (`getFullYear` / `getMonth` / `getDate`) — as the built-in tokens do. Avoid `toISOString()` / `getUTC*`, which shift the day by the local UTC offset (e.g. `2026-07-21` → `2026-07-20`). For a plain ISO string, prefer `display-format="YYYY-MM-DD"`.
131
-
132
- **Tokens** (matched longest-first; other characters pass through; wrap literal text containing token letters in `[ ]`):
133
-
134
- | Token | Meaning | Example (2026-07-21) |
135
- |-------|---------|----------------------|
136
- | `YYYY` | 4-digit year | `2026` |
137
- | `YY` | 2-digit year | `26` |
138
- | `MMMM` | Full month (locale) | `July` |
139
- | `MMM` | Short month (locale) | `Jul` |
140
- | `MM` | 2-digit month | `07` |
141
- | `M` | Month number | `7` |
142
- | `DD` | 2-digit day | `21` |
143
- | `D` | Day number | `21` |
144
-
145
- Named-month tokens (`MMMM`/`MMM`) respect `locale`; numeric formats are locale-independent. Existing consumers that set neither property are unaffected.
146
-
147
- ## Events
148
-
149
- | Event | Detail | Description |
150
- |-------|--------|-------------|
151
- | `rel-change` | `{ value: string \| null, date: Date \| null }` | Fired when selected date changes |
152
- | `rel-open-change` | `{ open: boolean }` | Fired when popover opens/closes |
153
-
154
- ## Keyboard Navigation
155
-
156
- ### Trigger Button
157
- - **Enter/Space**: Opens the popover
158
- - **Arrow Down**: Opens the popover
159
-
160
- ### Inside Calendar
161
- - **Arrow keys**: Navigate days (left/right) and weeks (up/down)
162
- - **Home/End**: Jump to week start/end
163
- - **PageUp/PageDown**: Change month
164
- - **Shift + PageUp/PageDown**: Change year
165
- - **Enter/Space**: Select focused day
166
- - **Escape**: Close popover
167
-
168
- ### Month/Year Dropdowns
169
- - **Tab**: Navigate between dropdowns
170
- - **Click**: Select month or year
171
-
172
- ## Calendar Features
173
-
174
- ### Month Dropdown
175
- - Lists all 12 months localized to the specified locale
176
- - Scroll through months quickly
177
- - Current month is highlighted
178
-
179
- ### Year Dropdown
180
- - Scrollable list of years
181
- - Range automatically calculated:
182
- - With min/max: Uses constrained range with buffer
183
- - Without: Defaults to [currentYear - 100, currentYear + 10]
184
- - Current year is highlighted
185
-
186
- ## Custom Disabled Dates
187
-
188
- Use the `isDateDisabled` property to implement custom logic:
189
-
190
- ```javascript
191
- const picker = document.querySelector('rel-date-picker');
192
-
193
- // Disable weekends
194
- picker.isDateDisabled = (date) => {
195
- const day = date.getDay();
196
- return day === 0 || day === 6;
197
- };
198
-
199
- // Disable specific dates
200
- const blackoutDates = ['2026-01-15', '2026-01-20', '2026-01-25'];
201
- picker.isDateDisabled = (date) => {
202
- const iso = date.toISOString().split('T')[0];
203
- return blackoutDates.includes(iso);
204
- };
205
-
206
- // Disable dates before today
207
- picker.isDateDisabled = (date) => {
208
- const today = new Date();
209
- today.setHours(0, 0, 0, 0);
210
- return date < today;
211
- };
212
- ```
213
-
214
- ## Complete Example
215
-
216
- ```html
217
- <rel-date-picker
218
- id="appointment-picker"
219
- label="Appointment Date"
220
- placeholder="Choose a date"
221
- min="2026-01-01"
222
- max="2026-12-31"
223
- clearable
224
- required
225
- ></rel-date-picker>
226
-
227
- <script>
228
- const picker = document.getElementById('appointment-picker');
229
-
230
- // Disable weekends
231
- picker.isDateDisabled = (date) => {
232
- const day = date.getDay();
233
- return day === 0 || day === 6;
234
- };
235
-
236
- // Handle selection
237
- picker.addEventListener('rel-change', (e) => {
238
- if (e.detail.value) {
239
- console.log('Appointment scheduled for:', e.detail.value);
240
- } else {
241
- console.log('Appointment cleared');
242
- }
243
- });
244
-
245
- // Handle popover state
246
- picker.addEventListener('rel-open-change', (e) => {
247
- console.log('Calendar', e.detail.open ? 'opened' : 'closed');
248
- });
249
- </script>
250
- ```
251
-
252
- ## Accessibility
253
-
254
- - Trigger button has proper `aria-haspopup`, `aria-expanded`, and `aria-label`
255
- - Calendar popover uses `role="dialog"`
256
- - Day buttons use `role="gridcell"` with proper `aria-label` and `aria-selected`
257
- - All interactive elements are keyboard accessible
258
- - Focus management:
259
- - Opening popover focuses first day
260
- - Closing popover returns focus to trigger
261
- - Visible focus rings on all interactive elements
262
- - Respects user's locale for month names and date formatting
263
-
264
- ## Styling
265
-
266
- The component uses design tokens from the Reliability Design System. All colors, spacing, and typography are inherited from CSS variables.
267
-
268
- Key tokens used:
269
- - `--rel-bg-*` / `--rel-text-*` / `--rel-border-*` semantic colors
270
- - `--rel-spacing-*` for spacing
271
- - `--rel-body-*` composite typography roles
272
- - `--rel-border-*` / `--rel-border-radius-*` tokens
273
- - `--rel-shadows-*` for popover shadow
274
- - Selected date: `--rel-bg-brand`
275
- - Today indicator: `--rel-bg-info`
276
- - Focus rings: `--rel-bg-info`
277
-
278
- ## Date Format
279
-
280
- - **Input/Output**: ISO 8601 format (YYYY-MM-DD)
281
- - **Display**: Localized format based on `locale` attribute
282
- - **Example**:
283
- - Value: `"2026-01-16"`
284
- - Display (en-US): `"January 16, 2026"`
285
- - Display (es-ES): `"16 de enero de 2026"`
286
-
287
- ## Browser Support
288
-
289
- Works in all modern browsers with ES2020 support and native Web Components.
1
+ # rel-date-picker
2
+
3
+ `<rel-date-picker>` is the single-date form field of the Reliability Design System (Figma "Date Picker"). It is a text field you can type a date into, with a popover calendar whose header pills drill into month and year grids, above Today / Tomorrow / Yesterday shortcut chips. The committed `value` is always an ISO `YYYY-MM-DD` string; the visible text follows `locale`, `display-format` or a `formatDate` callback. Use it wherever a form needs one date. For a from/to range use `<rel-range-picker>`, for an always-visible grid use `<rel-calendar>`, for a time of day use `<rel-time-picker>`.
4
+
5
+ ## Usage
6
+
7
+ ```html
8
+ <!-- Basic labelled field -->
9
+ <rel-date-picker label="Start date"></rel-date-picker>
10
+
11
+ <!-- Preselected, clearable, required (adds * to the label and aria-required) -->
12
+ <rel-date-picker label="Appointment" value="2026-01-16" clearable required></rel-date-picker>
13
+
14
+ <!-- Bounded to 2026, Monday-first grid -->
15
+ <rel-date-picker label="Delivery" min-date="2026-01-01" max-date="2026-12-31" week-start="mon"></rel-date-picker>
16
+
17
+ <!-- Field heights 32 / 40 / 48; fullwidth fills the parent -->
18
+ <rel-date-picker size="small" label="Small"></rel-date-picker>
19
+ <rel-date-picker size="medium" label="Medium" variant="outlined"></rel-date-picker>
20
+ <rel-date-picker size="large" label="Large" fullwidth></rel-date-picker>
21
+
22
+ <!-- Hide the Today / Tomorrow / Yesterday chip row (on by default) -->
23
+ <rel-date-picker label="Due" show-shortcuts="false"></rel-date-picker>
24
+
25
+ <!-- Helper and error text below the field -->
26
+ <rel-date-picker label="Due" helper-text="Defaults to the next business day"></rel-date-picker>
27
+ <rel-date-picker label="Due" error error-message="Pick a date after today"></rel-date-picker>
28
+
29
+ <!-- Fixed display format and locale (value stays ISO) -->
30
+ <rel-date-picker value="2026-07-21" display-format="DD/MM/YYYY"></rel-date-picker>
31
+ <rel-date-picker value="2026-07-21" locale="es-ES"></rel-date-picker>
32
+
33
+ <!-- Read-only, disabled, and native form submission via a hidden input -->
34
+ <rel-date-picker label="Created" value="2026-01-16" readonly></rel-date-picker>
35
+ <rel-date-picker label="Archived" value="2026-01-16" disabled></rel-date-picker>
36
+ <rel-date-picker name="start" label="Start" placeholder="YYYY-MM-DD"></rel-date-picker>
37
+ ```
38
+
39
+ ```js
40
+ const picker = document.querySelector("rel-date-picker");
41
+
42
+ // Disable individual days on top of min-date/max-date (property only)
43
+ picker.isDateDisabled = (date) => date.getDay() === 0 || date.getDay() === 6;
44
+
45
+ // Full control of the visible text; wins over display-format
46
+ picker.formatDate = (date) => `Q${Math.floor(date.getMonth() / 3) + 1} ${date.getFullYear()}`;
47
+
48
+ // Keep the popover open after a pick (a boolean attribute cannot be set to false in markup)
49
+ picker.closeOnSelect = false;
50
+
51
+ picker.addEventListener("rel-change", (e) => {
52
+ e.detail.value; // "2026-01-16" or null when cleared
53
+ e.detail.date; // Date at local midnight, or null
54
+ });
55
+ picker.addEventListener("rel-open-change", (e) => e.detail.open);
56
+ picker.addEventListener("rel-blur", () => {/* run validation */});
57
+ ```
58
+
59
+ ### Typed entry
60
+
61
+ The field is editable. Typed text is committed on Enter or when focus leaves the component; the parser (`date-parse.ts`) accepts ISO `2026-07-21`, numeric `21/7/2026` / `7/21/26`, month names `21 Jul 2026` / `July 21, 2026`, partial `21/7` (current year) or `21` (current month), and `20260721`. Two-digit years map to `20YY`. When day/month order is ambiguous (`3/4`), the order in `display-format` decides, else the locale's default numeric order. Shortcuts `t` / `today`, `t+7`, `t-3` resolve relative to today. Unparseable text shows "Invalid date", a date outside `min-date`/`max-date`/`isDateDisabled` shows "Date not available" — in both cases the text stays for correction and `value` is untouched; Escape reverts the text. Committing an empty field clears the value like the clear button does.
62
+
63
+ ### Display format
64
+
65
+ Without `display-format` or `formatDate` the field shows the locale long date (`July 21, 2026`, `21 de julio de 2026` for `es-ES`). `display-format` tokens (`date-format.ts`), matched longest-first with other characters passed through and literal text in `[ ]`: `YYYY` 2026 · `YY` 26 · `MMMM` July · `MMM` Jul · `MM` 07 · `M` 7 · `DD` 21 · `D` 21. Named-month tokens follow `locale`.
66
+
67
+ ### Deprecated aliases
68
+
69
+ ```html
70
+ <!-- min / max → min-date / max-date. Both still work; min-date/max-date win when both are set. No console notice is logged. -->
71
+ <rel-date-picker min="2026-01-01" max="2026-12-31"></rel-date-picker>
72
+ <!-- canonical -->
73
+ <rel-date-picker min-date="2026-01-01" max-date="2026-12-31"></rel-date-picker>
74
+ ```
75
+
76
+ <!-- readme-gen:start -->
77
+
78
+ <!-- Generated from rel-date-picker.ts — do not edit; run readme-generate.mjs -->
79
+
80
+ ## API
81
+
82
+ ### Attributes / Properties
83
+
84
+ | Property | Attribute | Type | Default | Description |
85
+ | --- | --- | --- | --- | --- |
86
+ | `value` | `value` | `string \| null` | `null` | Selected date as an ISO `YYYY-MM-DD` string, or `null` when empty; setting it also moves the popover to that month. Reflected. |
87
+ | `placeholder` | `placeholder` | `string` | `"Select date"` | Placeholder text shown while the field is empty (visual only; the accessible name comes from `label`, or "Select date" when unset). |
88
+ | `label` | `label` | `string \| null` | `null` | Visible label rendered above the field and wired to the input via `aria-labelledby`; `null` renders no label. |
89
+ | `disabled` | `disabled` | `boolean` | `false` | Disables the field, the icons and the popover; the host dims to 40% opacity. Reflected. |
90
+ | `required` | `required` | `boolean` | `false` | Appends a `*` to the label and sets `aria-required`; no validation is performed. |
91
+ | `readonly` | `readonly` | `boolean` | `false` | Makes the input read-only and stops the field, icon, Enter and ArrowDown from opening the popover. Reflected. |
92
+ | `minDate` | `min-date` | `string \| null` | `null` | Earliest selectable date (ISO `YYYY-MM-DD`); earlier days are disabled and typed dates before it are rejected. Wins over the deprecated `min`. |
93
+ | `maxDate` | `max-date` | `string \| null` | `null` | Latest selectable date (ISO `YYYY-MM-DD`); later days are disabled and typed dates after it are rejected. Wins over the deprecated `max`. |
94
+ | `weekStart` | `week-start` | `"sun" \| "mon"` | `"sun"` | First column of the calendar grid: `"sun"` (default) or `"mon"`. |
95
+ | `locale` | `locale` | `string` | `"en-US"` | BCP 47 locale for weekday/month names, the default long-date display, and day/month order when parsing ambiguous typed input. |
96
+ | `displayFormat` | `display-format` | `string \| null` | `null` | Token pattern for the displayed value (`YYYY`, `YY`, `MMMM`, `MMM`, `MM`, `M`, `DD`, `D`; literal text in `[ ]`), e.g. `DD/MM/YYYY`. Unset → the locale long date. Affects only the visible text, never `value`. |
97
+ | `formatDate` | — | `(date: Date) => string` | `undefined` | Callback with full control over the displayed value; wins over `displayFormat`. Assign it from JavaScript; it stays reactive so setting it after render re-renders the field. The Date it receives is at local midnight. Property only. |
98
+ | `open` | `open` | `boolean` | `false` | Whether the calendar popover is open; set it directly to open/close programmatically (focus then moves into the grid). Reflected. |
99
+ | `closeOnSelect` | `close-on-select` | `boolean` | `true` | Closes the popover after a day is picked in the grid (default `true`). |
100
+ | `clearable` | `clearable` | `boolean` | `false` | Shows a clear (×) icon while a value is set; clearing fires `rel-change` with `value: null`. |
101
+ | `showShortcuts` | `show-shortcuts` | `boolean` | `true` | Figma ".Date Picker Calendar" Show Shortcuts: renders the Today / Tomorrow / Yesterday chip row and its divider at the top of the popover. On by default — write `show-shortcuts="false"` to hide both (a plain boolean attribute could not express a default of `true`). The typed `T` / `T±N` shortcuts and the in-panel `T` key keep working either way. |
102
+ | `error` | `error` | `boolean` | `false` | Forces the error style (danger border, `aria-invalid`) and shows `errorMessage` below the field. Typed-entry parse errors set the same style on their own. |
103
+ | `errorMessage` | `error-message` | `string` | `undefined` | Text shown below the field while `error` is set (or a typed date failed to parse); falls back to `helperText`. |
104
+ | `helperText` | `helper-text` | `string` | `undefined` | Supporting text shown below the field when there is no error. |
105
+ | `name` | `name` | `string` | `undefined` | When set, renders a hidden `<input name>` carrying the ISO value so the picker submits with a native form. |
106
+ | `size` | `size` | `"small" \| "medium" \| "large"` | `"medium"` | Field height scale shared with rel-textfield / rel-select: `small` 32px, `medium` 40px (default), `large` 48px. |
107
+ | `variant` | `variant` | `"outlined"` | `"outlined"` | Visual style of the field; `outlined` is the only variant today. Reflected. |
108
+ | `fullWidth` | `fullwidth` | `boolean` | `false` | Stretches the host to fill its parent's width (attribute `fullwidth`); off by default so the field keeps its intrinsic inline width. Reflected. |
109
+
110
+ #### Deprecated (still supported — removal targeted for 3.0)
111
+
112
+ | Property | Attribute | Type | Use instead |
113
+ | --- | --- | --- | --- |
114
+ | `min` | `min` | `string \| null` | use minDate |
115
+ | `max` | `max` | `string \| null` | use maxDate |
116
+
117
+ ### Public fields / accessors
118
+
119
+ | Name | Type | Description |
120
+ | --- | --- | --- |
121
+ | `isDateDisabled` | `(date: Date) => boolean` | Custom predicate that disables individual days (return `true` to disable); applied on top of `minDate`/`maxDate` and also rejects typed input. Property only — assign it from JavaScript. |
122
+
123
+ ## Events
124
+
125
+ | Event | Detail | Bubbles / composed | Description |
126
+ | --- | --- | --- | --- |
127
+ | `rel-blur` | — | bubbles / composed | Fired when the text input loses focus (before any typed text is committed). No detail. |
128
+ | `rel-change` | `{ value: newValue, date: new Date(date), } / { value: null, date: null, } / { value: null, date: null }` | bubbles / composed | Fired when the value changes — grid pick, typed entry, shortcut, or clear. Detail: `{ value: string \| null, date: Date \| null }` (ISO `YYYY-MM-DD` and a local-midnight Date; both `null` when cleared). |
129
+ | `rel-open-change` | `{ open: this.open } / { open: false }` | bubbles / composed | Fired when the calendar popover opens or closes. Detail: `{ open: boolean }`. |
130
+
131
+ ## Slots
132
+
133
+ | Slot | Description |
134
+ | --- | --- |
135
+ | — | This element has no slots. |
136
+
137
+ ## CSS Parts
138
+
139
+ | Part | Description |
140
+ | --- | --- |
141
+ | `base` | Outer wrapper carrying the size class (`small` / `medium` / `large`) |
142
+ | `label` | The visible field label (rendered only when `label` is set) |
143
+ | `trigger` | The field box that wraps the text input and the clear/calendar icons |
144
+ | `value` | The editable text input inside the trigger |
145
+ | `shortcuts` | The Today / Tomorrow / Yesterday chip row at the top of the popover |
146
+
147
+ <!-- readme-gen:end -->
148
+
149
+ ## Accessibility
150
+
151
+ - The text input is a `role="combobox"` with `aria-haspopup="dialog"`, `aria-expanded`, `aria-controls` pointing at the panel, `aria-required` from `required`, `aria-invalid` when `error` is set or typed text failed to parse, and `aria-describedby` pointing at the helper/error line. Its name is the `label` (via `aria-labelledby`) or the fixed string "Select date" when no label is set; the required `*` is `aria-hidden`.
152
+ - The icons are real buttons: "Clear date" (only while `clearable` and a value is set) and "Open calendar" (carries `aria-expanded`).
153
+ - The popover is a `role="dialog"` named "Choose date". While it is open, Tab and Shift+Tab are trapped inside it (`trapTabKey`), and Escape closes it from anywhere in the document.
154
+ - The month and year pills are buttons carrying `aria-expanded`; pressing one swaps the panel body for a `role="grid"` of `role="gridcell"` cells ("Select month" / "Select year") with `aria-selected` on the current value. Every view is 252 px tall, so the panel never resizes as the user drills in.
155
+ - The day grid is `role="grid"` named "<Month> <Year>"; weeks are `role="row"`; each day is a `<button role="gridcell">` with the full long date as `aria-label`, `aria-selected`, `aria-current="date"` on today and native `disabled` for unavailable days. Only one cell is a Tab stop (last arrowed date → selected → today → first enabled).
156
+ - Focus: opening from the calendar icon, Enter, ArrowDown or by setting `open` moves focus into the grid (onto that Tab-stop cell) after 100 ms; opening by clicking into the text keeps focus in the input so typing keeps working. Closing via Escape, a pick or a shortcut returns focus to the input; an outside click closes without refocusing.
157
+ - Screen readers hear "<Month> <Year>" through the shared `announce()` region (`utils/announce.ts`) on every month/year change (chevrons, a month or year cell, PageUp/PageDown, arrowing across a month boundary), and the first and last year of the page (e.g. "2020 to 2031") when the years page changes. The helper/error line is a persistent `aria-live="polite"` region, so parse errors are read as they appear.
158
+
159
+ | Key (in the field) | Action |
160
+ | --- | --- |
161
+ | Enter | Nothing typed: open the popover. Text typed: commit it |
162
+ | ArrowDown | Open the popover; if already open, move focus into the grid |
163
+ | Escape | Revert uncommitted text and close the popover |
164
+ | Tab (popover open) | Cycle through the popover's controls |
165
+
166
+ | Key (in the grid) | Action |
167
+ | --- | --- |
168
+ | ArrowLeft / ArrowRight | Previous / next day (switches month at the edge) |
169
+ | ArrowUp / ArrowDown | Same weekday one week earlier / later |
170
+ | Home / End | First / last cell of the row |
171
+ | PageUp / PageDown | Previous / next month |
172
+ | Shift + PageUp / Shift + PageDown | Previous / next year |
173
+ | Enter / Space | Select the day; closes the popover unless `closeOnSelect` is false |
174
+ | T (anywhere in the popover, no modifier) | Select today |
175
+ | Escape | Close and return focus to the input |
176
+
177
+ | Key (month / year grid) | Action |
178
+ | --- | --- |
179
+ | Enter / Space on a pill | Open that grid; press the same pill again to return to the days |
180
+ | ArrowLeft / ArrowRight | Previous / next cell |
181
+ | ArrowUp / ArrowDown | Same column, one row up / down |
182
+ | Home / End | First / last cell of the grid |
183
+ | Enter / Space | Choose the cell — a year drills into the months, a month returns to the days |
184
+ | Escape | Back to the days grid, keeping the popover open |
185
+
186
+ ## Notes / Edge Cases
187
+
188
+ - `value` is always ISO `YYYY-MM-DD`; `display-format` and `formatDate` change only the visible text. The `Date` given to `formatDate`, `isDateDisabled` and `rel-change` is at local midnight — read it with `getFullYear()`/`getMonth()`/`getDate()`, never `toISOString()` (which can shift the day by the UTC offset). For a plain ISO display use `display-format="YYYY-MM-DD"`.
189
+ - `min`/`max` are deprecated aliases of `min-date`/`max-date`; when both spellings are present the canonical one wins. No runtime notice is logged.
190
+ - Leading and trailing cells of adjacent months are rendered but never selectable (unlike `rel-calendar`).
191
+ - The years grid shows one 12-year page at a time, anchored so the year in view sits in the seventh cell; the chevrons page by 12. In the months grid the chevrons step a year, and in the days grid a month. A month or year cell is disabled only when *every* day it covers falls outside `min-date`/`max-date`.
192
+ - The panel always reopens on the days grid, whichever view was showing when it closed.
193
+ - The field is Figma's TextField instance: `border-radius: xs` (4 px), 12 px inline padding at `medium`, a 4 px label gap and an 18 px suffix icon — the same geometry `rel-textfield` uses, so the two line up in a shared form row. Icon and inline padding step with `size` (16/18/20 px and 8/12/16 px).
194
+ - The panel is promoted to the browser top layer (`popover="manual"`), so it renders above `rel-modal` / `rel-drawer` and transformed or `overflow: hidden` ancestors, and it repositions on scroll/resize. It flips above the trigger when there is no room below, stays 8 px inside the viewport, is capped at 600 px tall (scrolls) and never wider than the viewport.
195
+ - Below-field text resolves as `errorMessage ?? typed-entry error ?? helperText` while in error, else `helperText`. A typed-entry error styles the field like `error` without setting the property.
196
+ - `readonly` and `disabled` both stop the popover from opening (field click, icon, Enter, ArrowDown); `disabled` also blocks all pointer events.
197
+ - `closeOnSelect` is a boolean attribute: it can only be turned off from JavaScript (`picker.closeOnSelect = false`). It affects grid picks only — typed entry and shortcuts always close the popover.
198
+ - The `name` hidden input submits an empty string while `value` is null.
199
+ - `size` is applied as a class on part `base` (not reflected); `variant` currently has the single value `outlined`.
200
+ - The host is `inline-block` with an intrinsic width (min 200 px) by default; `fullwidth` switches it to a block that fills the parent.