@tempoxyz/ds 0.3.10 → 0.3.11

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 (120) hide show
  1. package/dist/docs/AGENTS.md +9 -0
  2. package/dist/docs/components/accordion.md +489 -0
  3. package/dist/docs/components/address-card.md +147 -0
  4. package/dist/docs/components/agent-logo.md +194 -0
  5. package/dist/docs/components/alert-dialog.md +631 -0
  6. package/dist/docs/components/alert.md +448 -0
  7. package/dist/docs/components/amount-input.md +305 -0
  8. package/dist/docs/components/amount.md +794 -0
  9. package/dist/docs/components/app-shell.md +559 -0
  10. package/dist/docs/components/asset-chip.md +294 -0
  11. package/dist/docs/components/autocomplete.md +619 -0
  12. package/dist/docs/components/avatar.md +321 -0
  13. package/dist/docs/components/badge.md +339 -0
  14. package/dist/docs/components/badged-logo.md +116 -0
  15. package/dist/docs/components/banner.md +379 -0
  16. package/dist/docs/components/bar-chart.md +208 -0
  17. package/dist/docs/components/breadcrumbs.md +380 -0
  18. package/dist/docs/components/button-group.md +286 -0
  19. package/dist/docs/components/button.md +650 -0
  20. package/dist/docs/components/calendar.md +375 -0
  21. package/dist/docs/components/callout.md +96 -0
  22. package/dist/docs/components/checkbox-group.md +521 -0
  23. package/dist/docs/components/checkbox.md +467 -0
  24. package/dist/docs/components/choice-group.md +516 -0
  25. package/dist/docs/components/choicebox.md +641 -0
  26. package/dist/docs/components/code.md +100 -0
  27. package/dist/docs/components/combobox.md +939 -0
  28. package/dist/docs/components/container.md +257 -0
  29. package/dist/docs/components/copy-button.md +642 -0
  30. package/dist/docs/components/date-picker.md +514 -0
  31. package/dist/docs/components/dialog.md +1332 -0
  32. package/dist/docs/components/drawer.md +966 -0
  33. package/dist/docs/components/empty.md +340 -0
  34. package/dist/docs/components/field.md +570 -0
  35. package/dist/docs/components/fieldset.md +398 -0
  36. package/dist/docs/components/frame.md +434 -0
  37. package/dist/docs/components/gauge.md +299 -0
  38. package/dist/docs/components/get-started-visual.md +117 -0
  39. package/dist/docs/components/grid.md +288 -0
  40. package/dist/docs/components/hero-visual.md +155 -0
  41. package/dist/docs/components/hex.md +487 -0
  42. package/dist/docs/components/icon-tile.md +292 -0
  43. package/dist/docs/components/identicon.md +371 -0
  44. package/dist/docs/components/inline.md +233 -0
  45. package/dist/docs/components/inset.md +225 -0
  46. package/dist/docs/components/kbd.md +423 -0
  47. package/dist/docs/components/list-group.md +981 -0
  48. package/dist/docs/components/loading-dots.md +237 -0
  49. package/dist/docs/components/menu.md +934 -0
  50. package/dist/docs/components/native-select.md +204 -0
  51. package/dist/docs/components/network-logo.md +248 -0
  52. package/dist/docs/components/number-field.md +543 -0
  53. package/dist/docs/components/otp-field.md +616 -0
  54. package/dist/docs/components/pagination.md +516 -0
  55. package/dist/docs/components/popover.md +544 -0
  56. package/dist/docs/components/progress.md +388 -0
  57. package/dist/docs/components/qr.md +314 -0
  58. package/dist/docs/components/radio-group.md +528 -0
  59. package/dist/docs/components/secret-value.md +406 -0
  60. package/dist/docs/components/select.md +751 -0
  61. package/dist/docs/components/separator.md +379 -0
  62. package/dist/docs/components/sidebar-menu.md +922 -0
  63. package/dist/docs/components/skeleton.md +517 -0
  64. package/dist/docs/components/slider.md +539 -0
  65. package/dist/docs/components/snippet.md +424 -0
  66. package/dist/docs/components/spinner.md +216 -0
  67. package/dist/docs/components/split-bar.md +139 -0
  68. package/dist/docs/components/split-button.md +464 -0
  69. package/dist/docs/components/stack.md +299 -0
  70. package/dist/docs/components/status-chip.md +226 -0
  71. package/dist/docs/components/status-indicator.md +119 -0
  72. package/dist/docs/components/status-row.md +174 -0
  73. package/dist/docs/components/stepper.md +451 -0
  74. package/dist/docs/components/success-hero.md +157 -0
  75. package/dist/docs/components/surface.md +639 -0
  76. package/dist/docs/components/switch.md +472 -0
  77. package/dist/docs/components/table.md +967 -0
  78. package/dist/docs/components/tabs.md +627 -0
  79. package/dist/docs/components/tempo-logo.md +185 -0
  80. package/dist/docs/components/text-input.md +624 -0
  81. package/dist/docs/components/textarea.md +352 -0
  82. package/dist/docs/components/toast.md +535 -0
  83. package/dist/docs/components/token-logo.md +371 -0
  84. package/dist/docs/components/token.md +247 -0
  85. package/dist/docs/components/tooltip.md +490 -0
  86. package/dist/docs/components/verification-code.md +116 -0
  87. package/dist/docs/components/visual.md +249 -0
  88. package/dist/docs/components.md +203 -0
  89. package/dist/docs/foundations/accessibility.md +377 -0
  90. package/dist/docs/foundations/agents.md +150 -0
  91. package/dist/docs/foundations/color.md +522 -0
  92. package/dist/docs/foundations/content/tone.md +194 -0
  93. package/dist/docs/foundations/content/voice.md +194 -0
  94. package/dist/docs/foundations/content/writing-style.md +406 -0
  95. package/dist/docs/foundations/iconography.md +282 -0
  96. package/dist/docs/foundations/intent.md +360 -0
  97. package/dist/docs/foundations/layout.md +508 -0
  98. package/dist/docs/foundations/linter.md +296 -0
  99. package/dist/docs/foundations/motion.md +151 -0
  100. package/dist/docs/foundations/radius-and-padding.md +86 -0
  101. package/dist/docs/foundations/typography.md +266 -0
  102. package/dist/docs/index.md +137 -0
  103. package/dist/docs/introduction/faq.md +132 -0
  104. package/dist/docs/introduction/getting-started.md +377 -0
  105. package/dist/docs/patterns/blockchain-values.md +709 -0
  106. package/dist/docs/patterns/dashboards.md +638 -0
  107. package/dist/docs/patterns/destructive-actions.md +626 -0
  108. package/dist/docs/patterns/empty-states.md +612 -0
  109. package/dist/docs/patterns/errors-and-validation.md +808 -0
  110. package/dist/docs/patterns/feedback-and-status.md +518 -0
  111. package/dist/docs/patterns/forms.md +679 -0
  112. package/dist/docs/patterns/loading.md +630 -0
  113. package/dist/docs/patterns/navigation.md +397 -0
  114. package/dist/docs/patterns/payments.md +765 -0
  115. package/dist/docs/patterns/responsive-layout.md +997 -0
  116. package/dist/docs/patterns/tables-and-lists.md +964 -0
  117. package/dist/docs/products/tempo-console.md +671 -0
  118. package/dist/docs/products/tempo-performance.md +437 -0
  119. package/dist/docs/products/tempo-wallet.md +438 -0
  120. package/package.json +1 -1
@@ -0,0 +1,514 @@
1
+ # DatePicker
2
+
3
+ Shows the selected date and opens a calendar in a popup.
4
+
5
+ [View source and API](https://github.com/tempoxyz/ds/blob/main/src/web/components/DatePicker.tsx)
6
+
7
+ ## Overview
8
+
9
+ A date picker is a button that shows the selected date and opens a calendar in a popup. It has no text entry.
10
+
11
+ ## Examples
12
+
13
+ ### Basic
14
+
15
+ ```tsx
16
+ import { DatePicker } from '@tempoxyz/ds'
17
+
18
+ export function Demo() {
19
+ return (
20
+ <DatePicker.Root>
21
+ <DatePicker.Trigger />
22
+ <DatePicker.Popup>
23
+ <DatePicker.Calendar />
24
+ </DatePicker.Popup>
25
+ </DatePicker.Root>
26
+ )
27
+ }
28
+ ```
29
+
30
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/DatePicker/Basic.tsx)
31
+
32
+ ### Variant
33
+
34
+ Set `variant` on `DatePicker.Trigger` to `filled` (default) or `outlined`.
35
+
36
+ ```tsx
37
+ import { DatePicker, style } from '@tempoxyz/ds'
38
+
39
+ export function Demo() {
40
+ return (
41
+ <div {...styles.row()}>
42
+ {(['filled', 'outlined'] as const).map((variant) => (
43
+ <DatePicker.Root key={variant}>
44
+ <DatePicker.Trigger variant={variant} />
45
+ <DatePicker.Popup>
46
+ <DatePicker.Calendar />
47
+ </DatePicker.Popup>
48
+ </DatePicker.Root>
49
+ ))}
50
+ </div>
51
+ )
52
+ }
53
+
54
+ namespace styles {
55
+ export const row = style({
56
+ alignItems: 'flex-start',
57
+ display: 'flex',
58
+ flexWrap: 'wrap',
59
+ gap: '24',
60
+ })
61
+ }
62
+ ```
63
+
64
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/DatePicker/Variant.tsx)
65
+
66
+ ### Mode
67
+
68
+ Set `mode="range"` on `DatePicker.Root` to select a range. It defaults to `single`.
69
+
70
+ ```tsx
71
+ import { DatePicker } from '@tempoxyz/ds'
72
+
73
+ export function Demo() {
74
+ return (
75
+ <DatePicker.Root mode="range">
76
+ <DatePicker.Trigger placeholder="Select range" />
77
+ <DatePicker.Popup>
78
+ <DatePicker.Calendar />
79
+ </DatePicker.Popup>
80
+ </DatePicker.Root>
81
+ )
82
+ }
83
+ ```
84
+
85
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/DatePicker/Mode.tsx)
86
+
87
+ ### Invalid
88
+
89
+ Set `aria-invalid` on `DatePicker.Trigger` to mark it invalid.
90
+
91
+ ```tsx
92
+ import { DatePicker } from '@tempoxyz/ds'
93
+
94
+ export function Demo() {
95
+ return (
96
+ <DatePicker.Root>
97
+ <DatePicker.Trigger aria-invalid />
98
+ <DatePicker.Popup>
99
+ <DatePicker.Calendar />
100
+ </DatePicker.Popup>
101
+ </DatePicker.Root>
102
+ )
103
+ }
104
+ ```
105
+
106
+ [View example source](https://github.com/tempoxyz/ds/blob/main/docs/src/examples/demos/DatePicker/Invalid.tsx)
107
+
108
+ ## Anatomy
109
+
110
+ Import the component and assemble its parts.
111
+
112
+ ```tsx
113
+ import { DatePicker } from '@tempoxyz/ds'
114
+
115
+ <DatePicker.Root>
116
+ <DatePicker.Trigger />
117
+ <DatePicker.Popup>
118
+ <DatePicker.Calendar />
119
+ </DatePicker.Popup>
120
+ </DatePicker.Root>
121
+ ```
122
+
123
+ ## Guidelines
124
+
125
+ ### When to Use
126
+
127
+ * Enter a date as one field in a form, such as the expiry date of an API key.
128
+ * Enter a range with `mode="range"`, such as the period of a statement export.
129
+
130
+ ### When Not to Use
131
+
132
+ * Use [Calendar](/docs/components/calendar) when the grid stays visible, such as in a filter panel.
133
+ * Use [TextInput](/docs/components/text-input) for memorable dates far from today, such as a date of birth.
134
+ * Use [ChoiceGroup](/docs/components/choice-group) or [Select](/docs/components/select) for preset periods, such as 7D or Last 30 days.
135
+
136
+ ### Label the Trigger
137
+
138
+ The trigger shows only the date or the placeholder, and `Field.Label` doesn't link to it. Point its `aria-labelledby` at a visible label and at the trigger's own `id`.
139
+
140
+ **Do:** Put a visible label above the trigger and reference it with `aria-labelledby`.
141
+
142
+ ```tsx
143
+ /**
144
+ * Do example for "Label the Trigger" on the DatePicker page.
145
+ * Put a visible label above the trigger and reference it with `aria-labelledby`.
146
+ * @module
147
+ */
148
+ import { DatePicker, style } from '@tempoxyz/ds'
149
+
150
+ /** Renders the static preview, which the guideline card shows inert. */
151
+ export function Demo() {
152
+ return (
153
+ <div {...styles.field()}>
154
+ <span id="guideline-expiry-label" {...styles.label()}>
155
+ Key expires on
156
+ </span>
157
+ <DatePicker.Root defaultValue={new Date(2027, 0, 31)}>
158
+ <DatePicker.Trigger
159
+ aria-labelledby="guideline-expiry-label guideline-expiry"
160
+ id="guideline-expiry"
161
+ />
162
+ <DatePicker.Popup>
163
+ <DatePicker.Calendar />
164
+ </DatePicker.Popup>
165
+ </DatePicker.Root>
166
+ </div>
167
+ )
168
+ }
169
+
170
+ namespace styles {
171
+ export const field = style({ display: 'grid', rowGap: '8', width: '100% !custom' })
172
+
173
+ export const label = style({ color: 'content.primary', typography: 'body.b3Strong' })
174
+ }
175
+ ```
176
+
177
+ **Don't:** Leave the trigger to explain itself with Select date.
178
+
179
+ ```tsx
180
+ /**
181
+ * Don't example for "Label the Trigger" on the DatePicker page.
182
+ * Don't leave the trigger to explain itself with Select date.
183
+ * @module
184
+ */
185
+ import { DatePicker, style } from '@tempoxyz/ds'
186
+
187
+ /** Renders the static preview, which the guideline card shows inert. */
188
+ export function Demo() {
189
+ return (
190
+ <div {...styles.field()}>
191
+ <DatePicker.Root>
192
+ <DatePicker.Trigger />
193
+ <DatePicker.Popup>
194
+ <DatePicker.Calendar />
195
+ </DatePicker.Popup>
196
+ </DatePicker.Root>
197
+ </div>
198
+ )
199
+ }
200
+
201
+ namespace styles {
202
+ export const field = style({ display: 'grid', width: '100% !custom' })
203
+ }
204
+ ```
205
+
206
+ ### State Date Limits in Text
207
+
208
+ Pass `min`, `max`, and `isDateDisabled` to `DatePicker.Root`, which passes them to `DatePicker.Calendar`. Describe the limit below the trigger, and point `aria-describedby` at it.
209
+
210
+ **Do:** State the allowed range below the trigger, such as Choose a date within one year.
211
+
212
+ ```tsx
213
+ /**
214
+ * Do example for "State Date Limits in Text" on the DatePicker page.
215
+ * State the allowed range below the trigger, such as Choose a date within one year.
216
+ * @module
217
+ */
218
+ import { DatePicker, style } from '@tempoxyz/ds'
219
+
220
+ /** Renders the static preview, which the guideline card shows inert. */
221
+ export function Demo() {
222
+ return (
223
+ <div {...styles.field()}>
224
+ <span id="guideline-stated-limit-label" {...styles.label()}>
225
+ Key expires on
226
+ </span>
227
+ <DatePicker.Root max={new Date(2027, 9, 21)} min={new Date(2026, 9, 21)}>
228
+ <DatePicker.Trigger
229
+ aria-labelledby="guideline-stated-limit-label guideline-stated-limit"
230
+ aria-describedby="guideline-stated-limit-hint"
231
+ id="guideline-stated-limit"
232
+ />
233
+ <DatePicker.Popup>
234
+ <DatePicker.Calendar />
235
+ </DatePicker.Popup>
236
+ </DatePicker.Root>
237
+ <span id="guideline-stated-limit-hint" {...styles.hint()}>
238
+ Choose a date within one year.
239
+ </span>
240
+ </div>
241
+ )
242
+ }
243
+
244
+ namespace styles {
245
+ export const field = style({ display: 'grid', rowGap: '8', width: '100% !custom' })
246
+
247
+ export const label = style({ color: 'content.primary', typography: 'body.b3Strong' })
248
+
249
+ export const hint = style({ color: 'content.secondary', typography: 'body.b3' })
250
+ }
251
+ ```
252
+
253
+ **Don't:** Leave people to find the limit by paging through the calendar.
254
+
255
+ ```tsx
256
+ /**
257
+ * Don't example for "State Date Limits in Text" on the DatePicker page.
258
+ * Don't leave people to find the limit by paging through the calendar.
259
+ * @module
260
+ */
261
+ import { DatePicker, style } from '@tempoxyz/ds'
262
+
263
+ /** Renders the static preview, which the guideline card shows inert. */
264
+ export function Demo() {
265
+ return (
266
+ <div {...styles.field()}>
267
+ <span id="guideline-unstated-limit-label" {...styles.label()}>
268
+ Key expires on
269
+ </span>
270
+ <DatePicker.Root max={new Date(2027, 9, 21)} min={new Date(2026, 9, 21)}>
271
+ <DatePicker.Trigger
272
+ aria-labelledby="guideline-unstated-limit-label guideline-unstated-limit"
273
+ id="guideline-unstated-limit"
274
+ />
275
+ <DatePicker.Popup>
276
+ <DatePicker.Calendar />
277
+ </DatePicker.Popup>
278
+ </DatePicker.Root>
279
+ </div>
280
+ )
281
+ }
282
+
283
+ namespace styles {
284
+ export const field = style({ display: 'grid', rowGap: '8', width: '100% !custom' })
285
+
286
+ export const label = style({ color: 'content.primary', typography: 'body.b3Strong' })
287
+ }
288
+ ```
289
+
290
+ ### Show Errors in Text
291
+
292
+ Set `aria-invalid` on `DatePicker.Trigger` to fill it red. Put the error text below the trigger and point `aria-describedby` at it. `Field.Error` doesn't link to the trigger.
293
+
294
+ **Do:** Pair the red fill with error text that names the fix.
295
+
296
+ ```tsx
297
+ /**
298
+ * Do example for "Show Errors in Text" on the DatePicker page.
299
+ * Pair the red fill with error text that names the fix.
300
+ * @module
301
+ */
302
+ import { DatePicker, style } from '@tempoxyz/ds'
303
+
304
+ /** Renders the static preview, which the guideline card shows inert. */
305
+ export function Demo() {
306
+ return (
307
+ <div {...styles.field()}>
308
+ <span id="guideline-error-text-label" {...styles.label()}>
309
+ Key expires on
310
+ </span>
311
+ <DatePicker.Root defaultValue={new Date(2026, 9, 1)}>
312
+ <DatePicker.Trigger
313
+ aria-labelledby="guideline-error-text-label guideline-error-text"
314
+ aria-describedby="guideline-error-text-error"
315
+ aria-invalid
316
+ id="guideline-error-text"
317
+ />
318
+ <DatePicker.Popup>
319
+ <DatePicker.Calendar />
320
+ </DatePicker.Popup>
321
+ </DatePicker.Root>
322
+ <span id="guideline-error-text-error" {...styles.error()}>
323
+ Choose a date after today.
324
+ </span>
325
+ </div>
326
+ )
327
+ }
328
+
329
+ namespace styles {
330
+ export const field = style({ display: 'grid', rowGap: '8', width: '100% !custom' })
331
+
332
+ export const label = style({ color: 'content.primary', typography: 'body.b3Strong' })
333
+
334
+ export const error = style({ color: 'content.negative', typography: 'body.b3' })
335
+ }
336
+ ```
337
+
338
+ **Don't:** Mark the trigger invalid without saying what is wrong.
339
+
340
+ ```tsx
341
+ /**
342
+ * Don't example for "Show Errors in Text" on the DatePicker page.
343
+ * Don't mark the trigger invalid without saying what is wrong.
344
+ * @module
345
+ */
346
+ import { DatePicker, style } from '@tempoxyz/ds'
347
+
348
+ /** Renders the static preview, which the guideline card shows inert. */
349
+ export function Demo() {
350
+ return (
351
+ <div {...styles.field()}>
352
+ <span id="guideline-error-ring-label" {...styles.label()}>
353
+ Key expires on
354
+ </span>
355
+ <DatePicker.Root defaultValue={new Date(2026, 9, 1)}>
356
+ <DatePicker.Trigger
357
+ aria-labelledby="guideline-error-ring-label guideline-error-ring"
358
+ aria-invalid
359
+ id="guideline-error-ring"
360
+ />
361
+ <DatePicker.Popup>
362
+ <DatePicker.Calendar />
363
+ </DatePicker.Popup>
364
+ </DatePicker.Root>
365
+ </div>
366
+ )
367
+ }
368
+
369
+ namespace styles {
370
+ export const field = style({ display: 'grid', rowGap: '8', width: '100% !custom' })
371
+
372
+ export const label = style({ color: 'content.primary', typography: 'body.b3Strong' })
373
+ }
374
+ ```
375
+
376
+ ### Match the Fields Around It
377
+
378
+ `DatePicker.Trigger` is as tall as a [TextInput](/docs/components/text-input), at 48px. Use the same variant as the fields beside it.
379
+
380
+ **Do:** Give the trigger the variant of the inputs in the same row.
381
+
382
+ ```tsx
383
+ /**
384
+ * Do example for "Match the Fields Around It" on the DatePicker page.
385
+ * Give the trigger the variant of the inputs in the same row.
386
+ * @module
387
+ */
388
+ import { DatePicker, style, TextInput } from '@tempoxyz/ds'
389
+
390
+ /** Renders the static preview, which the guideline card shows inert. */
391
+ export function Demo() {
392
+ return (
393
+ <div {...styles.row()}>
394
+ <TextInput.Group {...styles.cell()}>
395
+ <TextInput.Control aria-label="Key name" defaultValue="Checkout server" />
396
+ </TextInput.Group>
397
+ <DatePicker.Root defaultValue={new Date(2027, 0, 31)}>
398
+ <DatePicker.Trigger aria-label="Key expires on" {...styles.cell()} />
399
+ <DatePicker.Popup>
400
+ <DatePicker.Calendar />
401
+ </DatePicker.Popup>
402
+ </DatePicker.Root>
403
+ </div>
404
+ )
405
+ }
406
+
407
+ namespace styles {
408
+ export const cell = style({ flex: '1 !custom', minWidth: '0 !custom' })
409
+
410
+ export const row = style({
411
+ alignItems: 'center',
412
+ display: 'flex',
413
+ gap: '8',
414
+ width: '100% !custom',
415
+ })
416
+ }
417
+ ```
418
+
419
+ **Don't:** Mix an `outlined` trigger with filled inputs.
420
+
421
+ ```tsx
422
+ /**
423
+ * Don't example for "Match the Fields Around It" on the DatePicker page.
424
+ * Don't mix an `outlined` trigger with filled inputs.
425
+ * @module
426
+ */
427
+ import { DatePicker, style, TextInput } from '@tempoxyz/ds'
428
+
429
+ /** Renders the static preview, which the guideline card shows inert. */
430
+ export function Demo() {
431
+ return (
432
+ <div {...styles.row()}>
433
+ <TextInput.Group {...styles.cell()}>
434
+ <TextInput.Control aria-label="Key name" defaultValue="Checkout server" />
435
+ </TextInput.Group>
436
+ <DatePicker.Root defaultValue={new Date(2027, 0, 31)}>
437
+ <DatePicker.Trigger aria-label="Key expires on" variant="outlined" {...styles.cell()} />
438
+ <DatePicker.Popup>
439
+ <DatePicker.Calendar />
440
+ </DatePicker.Popup>
441
+ </DatePicker.Root>
442
+ </div>
443
+ )
444
+ }
445
+
446
+ namespace styles {
447
+ export const cell = style({ flex: '1 !custom', minWidth: '0 !custom' })
448
+
449
+ export const row = style({
450
+ alignItems: 'center',
451
+ display: 'flex',
452
+ gap: '8',
453
+ width: '100% !custom',
454
+ })
455
+ }
456
+ ```
457
+
458
+ ## Content
459
+
460
+ * **Label:** Name the date, such as Key expires on or Start date.
461
+ * **Placeholder:** Keep Select date in single mode. In range mode, use Select dates.
462
+ * **Value:** The trigger formats it with `Intl.DateTimeFormat` in the medium date style for `locale`, such as Jan 31, 2027, and a range as one span.
463
+
464
+ ## Accessibility
465
+
466
+ A date picker renders a button that opens a calendar in a popup dialog. It follows the [WAI-ARIA Authoring Practices date picker dialog example](https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/examples/datepicker-dialog/), except that the popup is not modal.
467
+
468
+ ### Semantics
469
+
470
+ * **DatePicker.Trigger (button):** Announces that it opens a dialog, and whether the dialog is open.
471
+ * **DatePicker.Popup (dialog):** Renders a `dialog` named "Choose date" unless you pass `aria-label`.
472
+ * **DatePicker.Calendar (grid):** Uses the grid semantics described on [Calendar](/docs/components/calendar#accessibility).
473
+ * **Target Size (48px):** The trigger is above the 24px WCAG 2.2 minimum.
474
+
475
+ ### Keyboard
476
+
477
+ * **Move Focus to the Trigger (Tab):** Moves focus to the trigger.
478
+ * **Open the Popup (Enter or Space):** On the trigger, opens the popup and focuses a day.
479
+ * **Move Through Dates (Arrow keys):** Home, End, Page Up, and Page Down also move, as on [Calendar](/docs/components/calendar#keyboard).
480
+ * **Select a Day (Enter or Space):** On a day, selects it and closes the popup. In `range` mode, the popup closes after the end date.
481
+ * **Move Within the Popup (Tab and Shift+Tab):** Move between the month buttons and the day grid.
482
+ * **Close the Popup (Escape):** Closes the popup without a change, and returns focus to the trigger.
483
+
484
+ ### Focus
485
+
486
+ When the popup opens, focus moves to the selected day, or today. The popup doesn't trap focus, so Tab can leave it.
487
+
488
+ ### Your Responsibilities
489
+
490
+ * **Name the Trigger (aria-labelledby):** Point it at the visible label and the trigger, so the name includes the date.
491
+ * **Name Each Popup (aria-label):** If a page has several pickers, name each popup, such as "Choose start date".
492
+ * **Link the Error Text (aria-describedby):** Point it at the error text below the trigger.
493
+
494
+ ## Related
495
+
496
+ [Calendar](/docs/components/calendar)
497
+
498
+ Use for an inline month grid.
499
+
500
+ [TextInput](/docs/components/text-input)
501
+
502
+ Use for typed and native dates.
503
+
504
+ [Popover](/docs/components/popover)
505
+
506
+ Use for other anchored popups.
507
+
508
+ [Field](/docs/components/field)
509
+
510
+ Use for labels and errors on other controls.
511
+
512
+ [Forms](/docs/patterns/forms)
513
+
514
+ Covers placing a date among other fields.