@ceed/cds 1.24.1-next.3 → 1.26.0

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 (65) hide show
  1. package/dist/chunks/rehype-accent-FZRUD7VI.js +39 -0
  2. package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
  3. package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
  4. package/dist/components/DataTable/components.d.ts +2 -1
  5. package/dist/components/DataTable/hooks.d.ts +1 -1
  6. package/dist/components/DataTable/styled.d.ts +3 -1
  7. package/dist/components/DataTable/types.d.ts +11 -0
  8. package/dist/components/DataTable/utils.d.ts +2 -2
  9. package/dist/components/RadioTileGroup/RadioTileGroup.d.ts +56 -0
  10. package/dist/components/RadioTileGroup/index.d.ts +3 -0
  11. package/dist/components/data-display/DataTable.md +177 -1
  12. package/dist/components/data-display/InfoSign.md +74 -91
  13. package/dist/components/data-display/Typography.md +411 -94
  14. package/dist/components/feedback/CircularProgress.md +257 -0
  15. package/dist/components/feedback/Dialog.md +76 -62
  16. package/dist/components/feedback/Modal.md +430 -138
  17. package/dist/components/feedback/Skeleton.md +280 -0
  18. package/dist/components/feedback/llms.txt +2 -0
  19. package/dist/components/index.d.ts +1 -0
  20. package/dist/components/inputs/Autocomplete.md +356 -107
  21. package/dist/components/inputs/ButtonGroup.md +115 -104
  22. package/dist/components/inputs/CurrencyInput.md +183 -5
  23. package/dist/components/inputs/DatePicker.md +108 -431
  24. package/dist/components/inputs/DateRangePicker.md +131 -492
  25. package/dist/components/inputs/FilterableCheckboxGroup.md +145 -19
  26. package/dist/components/inputs/FormControl.md +361 -0
  27. package/dist/components/inputs/IconButton.md +137 -88
  28. package/dist/components/inputs/Input.md +204 -73
  29. package/dist/components/inputs/MonthPicker.md +95 -422
  30. package/dist/components/inputs/MonthRangePicker.md +89 -466
  31. package/dist/components/inputs/PercentageInput.md +185 -16
  32. package/dist/components/inputs/RadioButton.md +163 -35
  33. package/dist/components/inputs/RadioList.md +241 -0
  34. package/dist/components/inputs/RadioTileGroup.md +507 -0
  35. package/dist/components/inputs/Select.md +222 -326
  36. package/dist/components/inputs/Slider.md +334 -0
  37. package/dist/components/inputs/Switch.md +143 -376
  38. package/dist/components/inputs/Textarea.md +213 -10
  39. package/dist/components/inputs/Uploader/Uploader.md +145 -66
  40. package/dist/components/inputs/llms.txt +4 -0
  41. package/dist/components/navigation/Breadcrumbs.md +57 -308
  42. package/dist/components/navigation/Drawer.md +180 -0
  43. package/dist/components/navigation/Dropdown.md +98 -215
  44. package/dist/components/navigation/IconMenuButton.md +40 -502
  45. package/dist/components/navigation/InsetDrawer.md +281 -650
  46. package/dist/components/navigation/Link.md +31 -348
  47. package/dist/components/navigation/Menu.md +92 -285
  48. package/dist/components/navigation/MenuButton.md +55 -448
  49. package/dist/components/navigation/Pagination.md +47 -338
  50. package/dist/components/navigation/Stepper.md +160 -28
  51. package/dist/components/navigation/Tabs.md +57 -316
  52. package/dist/components/surfaces/Accordions.md +49 -804
  53. package/dist/components/surfaces/Card.md +97 -157
  54. package/dist/components/surfaces/Divider.md +83 -234
  55. package/dist/components/surfaces/Sheet.md +153 -328
  56. package/dist/guides/ThemeProvider.md +89 -0
  57. package/dist/guides/llms.txt +9 -0
  58. package/dist/index.browser.js +224 -0
  59. package/dist/index.browser.js.map +7 -0
  60. package/dist/index.cjs +726 -425
  61. package/dist/index.d.ts +1 -1
  62. package/dist/index.js +641 -396
  63. package/dist/llms.txt +9 -0
  64. package/framer/index.js +1 -163
  65. package/package.json +22 -17
@@ -1,8 +1,8 @@
1
1
  # DatePicker
2
2
 
3
- ## Introduction
3
+ DatePicker is a form input component that allows users to select a single date from a calendar popup or by typing directly into the input field. It provides flexible date formatting options, date range restrictions, and supports both controlled and uncontrolled modes.
4
4
 
5
- DatePicker is a form input component that allows users to select a single date from a calendar popup or by typing directly into the input field. It provides flexible date formatting options, date range restrictions, and supports both controlled and uncontrolled modes. DatePicker is essential for forms that require date input, such as booking systems, scheduling interfaces, and data filtering.
5
+ DatePicker is essential for any form that requires date input -- booking systems, scheduling interfaces, data filtering, and record keeping. It handles the complexity of date parsing, formatting, and validation so consumers can focus on business logic.
6
6
 
7
7
  ```tsx
8
8
  <DatePicker onChange={fn()} />
@@ -28,15 +28,6 @@ DatePicker is a form input component that allows users to select a single date f
28
28
  | disableFuture | — | — |
29
29
  | disablePast | — | — |
30
30
 
31
- > ⚠️ **Usage Warning** ⚠️
32
- >
33
- > DatePicker involves complex date handling logic:
34
- >
35
- > - **Format vs DisplayFormat**: `format` affects the value in `onChange`, while `displayFormat` affects what users see
36
- > - **Value format consistency**: The `value` and `defaultValue` props must match the `format` prop
37
- > - **Date validation**: Invalid date strings can cause unexpected behavior
38
- > - **Timezone considerations**: Be aware of timezone issues when working with dates
39
-
40
31
  ## Usage
41
32
 
42
33
  ```tsx
@@ -55,19 +46,14 @@ function DateForm() {
55
46
  }
56
47
  ```
57
48
 
58
- ## Examples
59
-
60
- ### Playground
61
-
62
- Interactive example with all controls.
63
-
64
- ```tsx
65
- <DatePicker onChange={fn()} />
66
- ```
49
+ > **Use built-in form props**
50
+ >
51
+ > This component natively supports form elements such as `label` and `helperText` props.
52
+ > When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
67
53
 
68
- ### Sizes
54
+ ## Sizes
69
55
 
70
- DatePicker supports three sizes for different layouts.
56
+ DatePicker supports three sizes (`sm`, `md`, `lg`) to fit different layout densities.
71
57
 
72
58
  ```tsx
73
59
  <Stack gap={2}>
@@ -77,9 +63,9 @@ DatePicker supports three sizes for different layouts.
77
63
  </Stack>
78
64
  ```
79
65
 
80
- ### With Label
66
+ ## Label and Helper Text
81
67
 
82
- Add a label above the date picker.
68
+ Use the `label` prop to provide a visible label, and `helperText` to give users additional guidance about expected input.
83
69
 
84
70
  ```tsx
85
71
  <DatePicker
@@ -88,10 +74,6 @@ Add a label above the date picker.
88
74
  />
89
75
  ```
90
76
 
91
- ### With Helper Text
92
-
93
- Provide additional guidance below the input.
94
-
95
77
  ```tsx
96
78
  <DatePicker
97
79
  onChange={fn()}
@@ -100,9 +82,9 @@ Provide additional guidance below the input.
100
82
  />
101
83
  ```
102
84
 
103
- ### Error State
85
+ ## Validation and Error State
104
86
 
105
- Show validation errors with error styling.
87
+ Set `error` to `true` and combine with `helperText` to communicate validation failures. Use the `required` prop to indicate mandatory fields.
106
88
 
107
89
  ```tsx
108
90
  <DatePicker
@@ -113,10 +95,6 @@ Show validation errors with error styling.
113
95
  />
114
96
  ```
115
97
 
116
- ### Required Field
117
-
118
- Mark the field as required in forms.
119
-
120
98
  ```tsx
121
99
  <DatePicker
122
100
  onChange={fn()}
@@ -126,9 +104,9 @@ Mark the field as required in forms.
126
104
  />
127
105
  ```
128
106
 
129
- ### Disabled
107
+ ## Disabled and Read-Only States
130
108
 
131
- Prevent user interaction when disabled.
109
+ The `disabled` prop prevents all interaction. The `readOnly` prop displays the value but blocks changes, while `inputReadOnly` disables keyboard typing but still allows calendar selection -- useful for mobile scenarios.
132
110
 
133
111
  ```tsx
134
112
  <DatePicker
@@ -137,31 +115,39 @@ Prevent user interaction when disabled.
137
115
  />
138
116
  ```
139
117
 
140
- ### Minimum Date
141
-
142
- Restrict selection to dates on or after a minimum date.
118
+ ```tsx
119
+ <DatePicker
120
+ onChange={fn()}
121
+ value="2024/04/01"
122
+ readOnly
123
+ />
124
+ ```
143
125
 
144
126
  ```tsx
145
127
  <DatePicker
146
128
  onChange={fn()}
147
- minDate="2024-04-10"
129
+ value="2024/04/01"
130
+ inputReadOnly
148
131
  />
149
132
  ```
150
133
 
151
- ### Maximum Date
134
+ ## Date Restrictions
152
135
 
153
- Restrict selection to dates on or before a maximum date.
136
+ Restrict selectable dates using `minDate`, `maxDate`, `disablePast`, `disableFuture`, or the flexible `shouldDisableDate` callback for custom logic such as disabling weekends or holidays.
154
137
 
155
138
  ```tsx
156
139
  <DatePicker
157
140
  onChange={fn()}
158
- maxDate="2024-04-10"
141
+ minDate="2024-04-10"
159
142
  />
160
143
  ```
161
144
 
162
- ### Disable Future Dates
163
-
164
- Prevent selection of dates in the future.
145
+ ```tsx
146
+ <DatePicker
147
+ onChange={fn()}
148
+ maxDate="2024-04-10"
149
+ />
150
+ ```
165
151
 
166
152
  ```tsx
167
153
  <DatePicker
@@ -170,20 +156,24 @@ Prevent selection of dates in the future.
170
156
  />
171
157
  ```
172
158
 
173
- ### Disable Past Dates
174
-
175
- Prevent selection of dates in the past.
159
+ ```tsx
160
+ <DatePicker
161
+ onChange={fn()}
162
+ disablePast
163
+ />
164
+ ```
176
165
 
177
166
  ```tsx
178
167
  <DatePicker
179
168
  onChange={fn()}
180
169
  disablePast
170
+ shouldDisableDate={date => [0, 6].includes(new Date(date).getDay()) || new Date(date).getTime() >= new Date().getTime() + 7 * 24 * 60 * 60 * 1000}
181
171
  />
182
172
  ```
183
173
 
184
- ### Controlled
174
+ ## Controlled vs Uncontrolled
185
175
 
186
- Parent component manages the date state.
176
+ DatePicker works in both controlled mode (you manage `value` via state) and uncontrolled mode (component manages its own state via `defaultValue`).
187
177
 
188
178
  ```tsx
189
179
  <Stack gap={2}>
@@ -201,10 +191,6 @@ Parent component manages the date state.
201
191
  </Stack>
202
192
  ```
203
193
 
204
- ### Uncontrolled
205
-
206
- Component manages its own state internally.
207
-
208
194
  ```tsx
209
195
  <DatePicker
210
196
  onChange={fn()}
@@ -214,9 +200,9 @@ Component manages its own state internally.
214
200
  />
215
201
  ```
216
202
 
217
- ### With Formats
203
+ ## Format and Display Format
218
204
 
219
- Different value formats for the `onChange` event.
205
+ The `format` prop determines the shape of the value emitted through `onChange`, while `displayFormat` controls what users see in the input field. This separation lets you keep a consistent API format (e.g. `YYYY-MM-DD`) while displaying a locale-appropriate format (e.g. `MM/DD/YYYY`).
220
206
 
221
207
  ```tsx
222
208
  <Stack gap={2}>
@@ -229,10 +215,6 @@ Different value formats for the `onChange` event.
229
215
  </Stack>
230
216
  ```
231
217
 
232
- ### With Display Formats
233
-
234
- Different display formats shown in the input field.
235
-
236
218
  ```tsx
237
219
  <Stack gap={2}>
238
220
  <DatePicker {...args} value={value1} label="YYYY.MM.DD" name="YYYY.MM.DD" displayFormat="YYYY.MM.DD" onChange={e => {
@@ -262,33 +244,38 @@ Different display formats shown in the input field.
262
244
  </Stack>
263
245
  ```
264
246
 
265
- ### Input Read Only
247
+ **Supported format tokens:**
266
248
 
267
- Allow calendar selection only, prevent typing.
249
+ | Token | Description | Example |
250
+ | ------ | ------------- | ------- |
251
+ | `YYYY` | 4-digit year | 2024 |
252
+ | `MM` | 2-digit month | 04 |
253
+ | `DD` | 2-digit day | 15 |
268
254
 
269
- ```tsx
270
- <DatePicker
271
- onChange={fn()}
272
- value="2024/04/01"
273
- inputReadOnly
274
- />
275
- ```
255
+ Common patterns: `YYYY/MM/DD` (default), `YYYY-MM-DD` (ISO 8601), `MM/DD/YYYY` (US), `DD/MM/YYYY` (EU), `DD.MM.YYYY` (German), `YYYY.MM.DD` (East Asian).
256
+
257
+ ## Additional Features
276
258
 
277
- ### Read Only
259
+ ### Reset Button
278
260
 
279
- Fully read-only state with no interaction.
261
+ Pair DatePicker with an external reset button to programmatically clear the value.
280
262
 
281
263
  ```tsx
282
- <DatePicker
283
- onChange={fn()}
284
- value="2024/04/01"
285
- readOnly
286
- />
264
+ <div style={{
265
+ display: 'flex',
266
+ gap: '10px'
267
+ }}>
268
+ <DatePicker {...props} value={value} onChange={event => {
269
+ onChange?.(event);
270
+ setValue(event.target.value);
271
+ }} />
272
+ <Button onClick={() => setValue('')}>Reset</Button>
273
+ </div>
287
274
  ```
288
275
 
289
276
  ### Hide Clear Button
290
277
 
291
- Remove the clear button from the calendar popup.
278
+ Remove the built-in clear button from the calendar popup when clearing is not desired.
292
279
 
293
280
  ```tsx
294
281
  <DatePicker
@@ -298,21 +285,9 @@ Remove the clear button from the calendar popup.
298
285
  />
299
286
  ```
300
287
 
301
- ### Custom Date Disabling
302
-
303
- Use `shouldDisableDate` to disable specific dates.
304
-
305
- ```tsx
306
- <DatePicker
307
- onChange={fn()}
308
- disablePast
309
- shouldDisableDate={date => [0, 6].includes(new Date(date).getDay()) || new Date(date).getTime() >= new Date().getTime() + 7 * 24 * 60 * 60 * 1000}
310
- />
311
- ```
312
-
313
288
  ### Synchronized Date Pickers
314
289
 
315
- Multiple date pickers sharing the same value.
290
+ Multiple DatePicker instances can share the same value for dependent field scenarios.
316
291
 
317
292
  ```tsx
318
293
  <Stack gap={2}>
@@ -324,25 +299,6 @@ Multiple date pickers sharing the same value.
324
299
  </Stack>
325
300
  ```
326
301
 
327
- ## When to Use
328
-
329
- ### ✅ Good Use Cases
330
-
331
- - **Form date fields**: Birthdays, appointment dates, due dates
332
- - **Booking systems**: Hotel check-in/out, flight dates, reservations
333
- - **Scheduling**: Event dates, meeting times, deadlines
334
- - **Data filtering**: Date range filters in reports and dashboards
335
- - **Historical data**: Recording when events occurred
336
- - **Deadline selection**: Task due dates, project milestones
337
-
338
- ### ❌ When Not to Use
339
-
340
- - **Date ranges**: Use DateRangePicker for start/end date pairs
341
- - **Month/Year only**: Use MonthPicker for month-level granularity
342
- - **Time selection**: Use a dedicated TimePicker component
343
- - **Relative dates**: For "last 7 days" style filters, use dropdown selection
344
- - **Known date sets**: For selecting from predefined dates, consider Select or RadioButton
345
-
346
302
  ## Common Use Cases
347
303
 
348
304
  ### Form with Validation
@@ -357,7 +313,6 @@ function BookingForm() {
357
313
  setError('Please select a check-in date');
358
314
  return;
359
315
  }
360
- // Submit form
361
316
  };
362
317
 
363
318
  return (
@@ -374,62 +329,21 @@ function BookingForm() {
374
329
  disablePast
375
330
  required
376
331
  />
377
- <Button type="submit">Book Now</Button>
378
332
  </form>
379
333
  );
380
334
  }
381
335
  ```
382
336
 
383
- ### Date Range Restriction
384
-
385
- ```tsx
386
- function EventScheduler() {
387
- const [eventDate, setEventDate] = useState('');
388
-
389
- // Event must be within the next 30 days
390
- const today = new Date();
391
- const maxDate = new Date(today.getTime() + 30 * 24 * 60 * 60 * 1000);
392
-
393
- const formatDate = (date) => {
394
- const year = date.getFullYear();
395
- const month = String(date.getMonth() + 1).padStart(2, '0');
396
- const day = String(date.getDate()).padStart(2, '0');
397
- return `${year}/${month}/${day}`;
398
- };
399
-
400
- return (
401
- <DatePicker
402
- label="Event Date"
403
- value={eventDate}
404
- onChange={(e) => setEventDate(e.target.value)}
405
- minDate={formatDate(today)}
406
- maxDate={formatDate(maxDate)}
407
- helperText="Select a date within the next 30 days"
408
- />
409
- );
410
- }
411
- ```
412
-
413
- ### Custom Date Validation
337
+ ### Custom Date Disabling (Weekdays Only)
414
338
 
415
339
  ```tsx
416
340
  function AppointmentPicker() {
417
341
  const [date, setDate] = useState('');
418
342
 
419
- // Disable weekends and holidays
420
- const shouldDisableDate = (dateString) => {
421
- const date = new Date(dateString);
422
- const day = date.getDay();
423
-
424
- // Disable weekends (Saturday = 6, Sunday = 0)
425
- if (day === 0 || day === 6) return true;
426
-
427
- // Disable specific holidays
428
- const holidays = ['2024/01/01', '2024/12/25'];
429
- if (holidays.includes(dateString)) return true;
430
-
431
- return false;
432
- };
343
+ const shouldDisableDate = useCallback((dateString: string) => {
344
+ const day = new Date(dateString).getDay();
345
+ return day === 0 || day === 6; // Disable weekends
346
+ }, []);
433
347
 
434
348
  return (
435
349
  <DatePicker
@@ -438,326 +352,89 @@ function AppointmentPicker() {
438
352
  onChange={(e) => setDate(e.target.value)}
439
353
  shouldDisableDate={shouldDisableDate}
440
354
  disablePast
441
- helperText="Weekdays only, excluding holidays"
355
+ helperText="Weekdays only"
442
356
  />
443
357
  );
444
358
  }
445
359
  ```
446
360
 
447
- ### Different Regional Formats
361
+ ### Locale-Aware Display
448
362
 
449
363
  ```tsx
450
- function RegionalDateForm({ locale }) {
364
+ function RegionalDateField({ locale }: { locale: string }) {
451
365
  const [date, setDate] = useState('');
452
366
 
453
- // Format based on locale
454
- const getDisplayFormat = () => {
455
- switch (locale) {
456
- case 'en-US':
457
- return 'MM/DD/YYYY';
458
- case 'en-GB':
459
- return 'DD/MM/YYYY';
460
- case 'de-DE':
461
- return 'DD.MM.YYYY';
462
- default:
463
- return 'YYYY/MM/DD';
464
- }
465
- };
367
+ const displayFormat = locale === 'en-US' ? 'MM/DD/YYYY'
368
+ : locale === 'en-GB' ? 'DD/MM/YYYY'
369
+ : 'YYYY-MM-DD';
466
370
 
467
371
  return (
468
372
  <DatePicker
469
373
  label="Date"
470
374
  value={date}
471
375
  onChange={(e) => setDate(e.target.value)}
472
- format="YYYY/MM/DD" // Internal value format stays consistent
473
- displayFormat={getDisplayFormat()} // Display varies by locale
474
- />
475
- );
476
- }
477
- ```
478
-
479
- ### Mobile-Friendly Input
480
-
481
- ```tsx
482
- function MobileDatePicker() {
483
- const [date, setDate] = useState('');
484
-
485
- return (
486
- <DatePicker
487
- label="Select Date"
488
- value={date}
489
- onChange={(e) => setDate(e.target.value)}
490
- inputReadOnly // Prevent keyboard on mobile, use calendar only
491
- size="lg" // Larger touch targets
376
+ format="YYYY/MM/DD"
377
+ displayFormat={displayFormat}
492
378
  />
493
379
  );
494
380
  }
495
381
  ```
496
382
 
497
- ### Form Integration with React Hook Form
498
-
499
- ```tsx
500
- function DateFormWithHookForm() {
501
- const { register, handleSubmit, setValue, watch } = useForm();
502
- const birthDate = watch('birthDate');
503
-
504
- return (
505
- <form onSubmit={handleSubmit(onSubmit)}>
506
- <DatePicker
507
- label="Birth Date"
508
- value={birthDate || ''}
509
- onChange={(e) => setValue('birthDate', e.target.value)}
510
- disableFuture
511
- required
512
- />
513
- </form>
514
- );
515
- }
516
- ```
517
-
518
- ## Props and Customization
519
-
520
- ### Key Props
521
-
522
- | Prop | Type | Default | Description |
523
- | ------------------- | ----------------------------------------------------------- | ---------------- | ------------------------------------------- |
524
- | `value` | `string` | - | Controlled date value (must match `format`) |
525
- | `defaultValue` | `string` | - | Default value for uncontrolled mode |
526
- | `onChange` | `(e: { target: { name?: string; value: string } }) => void` | - | Change handler |
527
- | `format` | `string` | `'YYYY/MM/DD'` | Format for `value` and `onChange` |
528
- | `displayFormat` | `string` | Same as `format` | Format displayed in the input |
529
- | `label` | `string` | - | Label text |
530
- | `helperText` | `string` | - | Helper text below input |
531
- | `error` | `boolean` | `false` | Error state |
532
- | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Component size |
533
- | `disabled` | `boolean` | `false` | Disabled state |
534
- | `required` | `boolean` | `false` | Required field indicator |
535
- | `minDate` | `string` | - | Minimum selectable date |
536
- | `maxDate` | `string` | - | Maximum selectable date |
537
- | `disableFuture` | `boolean` | `false` | Disable all future dates |
538
- | `disablePast` | `boolean` | `false` | Disable all past dates |
539
- | `shouldDisableDate` | `(date: string) => boolean` | - | Custom date disable function |
540
- | `inputReadOnly` | `boolean` | `false` | Prevent typing, calendar only |
541
- | `readOnly` | `boolean` | `false` | Fully read-only |
542
- | `hideClearButton` | `boolean` | `false` | Hide clear button in calendar |
543
-
544
- ### Format vs DisplayFormat
545
-
546
- Understanding the difference between `format` and `displayFormat`:
547
-
548
- ```tsx
549
- // format: Affects the value in onChange
550
- // displayFormat: Affects what users see in the input
551
-
552
- <DatePicker
553
- format="YYYY-MM-DD" // onChange returns "2024-04-15"
554
- displayFormat="MM/DD/YYYY" // Input shows "04/15/2024"
555
- onChange={(e) => {
556
- console.log(e.target.value); // "2024-04-15"
557
- }}
558
- />
559
- ```
560
-
561
- ### Supported Format Tokens
562
-
563
- | Token | Description | Example |
564
- | ------ | ------------- | ------- |
565
- | `YYYY` | 4-digit year | 2024 |
566
- | `MM` | 2-digit month | 04 |
567
- | `DD` | 2-digit day | 15 |
568
-
569
- Common format patterns:
570
-
571
- - `YYYY/MM/DD` - ISO-like (default)
572
- - `YYYY-MM-DD` - ISO 8601
573
- - `MM/DD/YYYY` - US format
574
- - `DD/MM/YYYY` - European format
575
- - `DD.MM.YYYY` - German format
576
- - `YYYY.MM.DD` - East Asian format
577
-
578
- ### Controlled vs Uncontrolled
579
-
580
- ```tsx
581
- // Uncontrolled - component manages state
582
- <DatePicker
583
- defaultValue="2024/04/01"
584
- onChange={(e) => console.log(e.target.value)}
585
- />
586
-
587
- // Controlled - you manage state
588
- const [date, setDate] = useState('2024/04/01');
589
- <DatePicker
590
- value={date}
591
- onChange={(e) => setDate(e.target.value)}
592
- />
593
- ```
594
-
595
- ## Accessibility
596
-
597
- DatePicker includes built-in accessibility features:
598
-
599
- ### ARIA Attributes
600
-
601
- - Input has proper `role="textbox"`
602
- - Calendar button has `aria-label="Toggle Calendar"`
603
- - Calendar popup uses `role="tooltip"` with proper labeling
604
- - Date buttons announce the full date to screen readers
605
-
606
- ### Keyboard Navigation
607
-
608
- - **Tab**: Move focus between input and calendar button
609
- - **Enter/Space**: Open calendar when focused on button
610
- - **Arrow Keys**: Navigate within calendar
611
- - **Escape**: Close calendar popup
612
- - **Enter**: Select focused date
613
-
614
- ### Screen Reader Support
615
-
616
- ```tsx
617
- // Dates are announced with full context
618
- <button aria-label="April 15, 2024">15</button>
619
-
620
- // Navigation buttons are descriptive
621
- <button aria-label="Previous Month">←</button>
622
- <button aria-label="Next Month">→</button>
623
- ```
624
-
625
- ### Focus Management
626
-
627
- - Focus moves to calendar when opened
628
- - Focus returns to input when calendar closes
629
- - Clear visual focus indicators on all interactive elements
630
-
631
383
  ## Best Practices
632
384
 
633
- ### Do
634
-
635
- 1. **Use appropriate date restrictions**: Set min/max dates when applicable
385
+ 1. **Always provide a label**
636
386
 
637
387
  ```tsx
638
- // Good: Reasonable date constraints
639
- <DatePicker
640
- label="Birth Date"
641
- disableFuture
642
- minDate="1900/01/01"
643
- />
644
- ```
645
-
646
- 2. **Provide clear labels and helper text**: Guide users on expected input
388
+ {/* Do */}
389
+ <DatePicker label="Birth Date" />
647
390
 
648
- ```tsx
649
- // Good: Clear guidance
650
- <DatePicker
651
- label="Preferred Delivery Date"
652
- helperText="Select a weekday within the next 2 weeks"
653
- />
391
+ {/* Don't */}
392
+ <DatePicker placeholder="Birth Date" />
654
393
  ```
655
394
 
656
- 3. **Use consistent formats**: Match your application's locale conventions
395
+ 2. **Keep value format consistent with the `format` prop**
657
396
 
658
397
  ```tsx
659
- // Good: Consistent with app locale
660
- <DatePicker
661
- format="YYYY-MM-DD" // API format
662
- displayFormat="MM/DD/YYYY" // US locale display
663
- />
664
- ```
398
+ {/* Do */}
399
+ <DatePicker format="YYYY/MM/DD" value="2024/04/15" />
665
400
 
666
- 4. **Handle empty states**: Consider what empty value means in your context
667
-
668
- ```tsx
669
- // ✅ Good: Clear empty state handling
670
- const [date, setDate] = useState('');
671
- {date ? <span>Selected: {date}</span> : <span>No date selected</span>}
401
+ {/* Don't -- mismatched format causes unexpected behavior */}
402
+ <DatePicker format="YYYY/MM/DD" value="04/15/2024" />
672
403
  ```
673
404
 
674
- ### Don't
675
-
676
- 1. **Don't use inconsistent value formats**: Always match value format to `format` prop
405
+ 3. **Use `displayFormat` to separate API format from UI format**
677
406
 
678
407
  ```tsx
679
- // Bad: Mismatched formats
680
- <DatePicker
681
- format="YYYY/MM/DD"
682
- value="04/15/2024" // Wrong! Should be "2024/04/15"
683
- />
684
- ```
408
+ {/* Do -- consistent API format, locale-appropriate display */}
409
+ <DatePicker format="YYYY-MM-DD" displayFormat="MM/DD/YYYY" />
685
410
 
686
- 2. **Don't disable validation feedback**: Show errors when dates are invalid
687
-
688
- ```tsx
689
- // ❌ Bad: No error feedback
690
- <DatePicker value={invalidDate} />
691
-
692
- // ✅ Good: Show validation state
693
- <DatePicker value={date} error={!isValid} helperText={errorMessage} />
411
+ {/* Don't -- changing format just for display affects onChange values */}
412
+ <DatePicker format="MM/DD/YYYY" />
694
413
  ```
695
414
 
696
- 3. **Don't forget mobile users**: Use `inputReadOnly` for better mobile experience
697
-
698
- 4. **Don't use placeholder as label**: Use the `label` prop instead
415
+ 4. **Set appropriate date boundaries for your use case**
699
416
 
700
417
  ```tsx
701
- // Bad: Placeholder as label
702
- <DatePicker placeholder="Birth Date" />
418
+ {/* Do */}
419
+ <DatePicker label="Birth Date" disableFuture minDate="1900/01/01" />
703
420
 
704
- // Good: Proper label
421
+ {/* Don't -- unrestricted date range for a birth date field */}
705
422
  <DatePicker label="Birth Date" />
706
423
  ```
707
424
 
708
- ## Performance Considerations
709
-
710
- ### Memoize shouldDisableDate
711
-
712
- For complex date validation logic, memoize the function:
425
+ 5. **Show validation feedback with error and helperText**
713
426
 
714
427
  ```tsx
715
- const shouldDisableDate = useCallback((dateString) => {
716
- const date = new Date(dateString);
717
- // Complex validation logic
718
- return isHoliday(date) || isWeekend(date);
719
- }, [holidays]); // Only recreate when holidays change
720
-
721
- <DatePicker shouldDisableDate={shouldDisableDate} />
722
- ```
428
+ {/* Do */}
429
+ <DatePicker error={!isValid} helperText={errorMessage} />
723
430
 
724
- ### Controlled Component Optimization
725
-
726
- When using controlled mode, avoid unnecessary state updates:
727
-
728
- ```tsx
729
- const handleChange = useCallback((e) => {
730
- setDate(e.target.value);
731
- }, []);
732
-
733
- <DatePicker value={date} onChange={handleChange} />
431
+ {/* Don't -- silently ignore invalid state */}
432
+ <DatePicker value={invalidDate} />
734
433
  ```
735
434
 
736
- ### Format Conversion
737
-
738
- When working with APIs that expect different date formats:
739
-
740
- ```tsx
741
- function DateField({ value, onChange, apiFormat = 'YYYY-MM-DD' }) {
742
- // Convert from API format to display
743
- const displayValue = useMemo(() =>
744
- convertFormat(value, apiFormat, 'YYYY/MM/DD'),
745
- [value, apiFormat]
746
- );
747
-
748
- const handleChange = useCallback((e) => {
749
- // Convert back to API format
750
- onChange(convertFormat(e.target.value, 'YYYY/MM/DD', apiFormat));
751
- }, [onChange, apiFormat]);
752
-
753
- return (
754
- <DatePicker
755
- value={displayValue}
756
- onChange={handleChange}
757
- format="YYYY/MM/DD"
758
- />
759
- );
760
- }
761
- ```
435
+ ## Accessibility
762
436
 
763
- DatePicker is a fundamental form component for date input. Choose appropriate date restrictions based on your use case, maintain consistent formats throughout your application, and provide clear guidance to users for the best experience.
437
+ - **Keyboard navigation**: Tab moves focus between the input and the calendar toggle button. Arrow keys navigate dates within the open calendar. Enter selects the focused date, and Escape closes the calendar popup.
438
+ - **ARIA attributes**: The calendar toggle button has `aria-label="Toggle Calendar"`. The calendar popup uses `role="tooltip"` with descriptive labeling. Each date button announces the full date to screen readers.
439
+ - **Focus management**: Focus moves into the calendar when opened and returns to the input when the calendar closes. All interactive elements have clear focus indicators.
440
+ - **Use `inputReadOnly` on mobile**: When targeting touch devices, set `inputReadOnly` to prevent the virtual keyboard from appearing and guide users toward the calendar picker instead.