@ceed/ads 1.23.3 → 1.23.5

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