@ceed/cds 1.24.1-next.3 → 1.25.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.
- package/dist/chunks/rehype-accent-FZRUD7VI.js +39 -0
- package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
- package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
- package/dist/components/DataTable/components.d.ts +2 -1
- package/dist/components/DataTable/styled.d.ts +3 -1
- package/dist/components/DataTable/types.d.ts +1 -0
- package/dist/components/RadioTileGroup/RadioTileGroup.d.ts +56 -0
- package/dist/components/RadioTileGroup/index.d.ts +3 -0
- package/dist/components/data-display/DataTable.md +77 -1
- package/dist/components/data-display/InfoSign.md +74 -91
- package/dist/components/data-display/Typography.md +411 -94
- package/dist/components/feedback/CircularProgress.md +257 -0
- package/dist/components/feedback/Dialog.md +76 -62
- package/dist/components/feedback/Modal.md +430 -138
- package/dist/components/feedback/Skeleton.md +280 -0
- package/dist/components/feedback/llms.txt +2 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/inputs/Autocomplete.md +356 -107
- package/dist/components/inputs/ButtonGroup.md +115 -104
- package/dist/components/inputs/CurrencyInput.md +183 -5
- package/dist/components/inputs/DatePicker.md +108 -431
- package/dist/components/inputs/DateRangePicker.md +131 -492
- package/dist/components/inputs/FilterableCheckboxGroup.md +145 -19
- package/dist/components/inputs/FormControl.md +361 -0
- package/dist/components/inputs/IconButton.md +137 -88
- package/dist/components/inputs/Input.md +204 -73
- package/dist/components/inputs/MonthPicker.md +95 -422
- package/dist/components/inputs/MonthRangePicker.md +89 -466
- package/dist/components/inputs/PercentageInput.md +185 -16
- package/dist/components/inputs/RadioButton.md +163 -35
- package/dist/components/inputs/RadioList.md +241 -0
- package/dist/components/inputs/RadioTileGroup.md +507 -0
- package/dist/components/inputs/Select.md +222 -326
- package/dist/components/inputs/Slider.md +334 -0
- package/dist/components/inputs/Switch.md +143 -376
- package/dist/components/inputs/Textarea.md +213 -10
- package/dist/components/inputs/Uploader/Uploader.md +145 -66
- package/dist/components/inputs/llms.txt +4 -0
- package/dist/components/navigation/Breadcrumbs.md +57 -308
- package/dist/components/navigation/Drawer.md +180 -0
- package/dist/components/navigation/Dropdown.md +98 -215
- package/dist/components/navigation/IconMenuButton.md +40 -502
- package/dist/components/navigation/InsetDrawer.md +281 -650
- package/dist/components/navigation/Link.md +31 -348
- package/dist/components/navigation/Menu.md +92 -285
- package/dist/components/navigation/MenuButton.md +55 -448
- package/dist/components/navigation/Pagination.md +47 -338
- package/dist/components/navigation/Stepper.md +160 -28
- package/dist/components/navigation/Tabs.md +57 -316
- package/dist/components/surfaces/Accordions.md +49 -804
- package/dist/components/surfaces/Card.md +97 -157
- package/dist/components/surfaces/Divider.md +83 -234
- package/dist/components/surfaces/Sheet.md +153 -328
- package/dist/guides/ThemeProvider.md +89 -0
- package/dist/guides/llms.txt +9 -0
- package/dist/index.browser.js +224 -0
- package/dist/index.browser.js.map +7 -0
- package/dist/index.cjs +648 -390
- package/dist/index.d.ts +1 -1
- package/dist/index.js +563 -361
- package/dist/llms.txt +9 -0
- package/framer/index.js +1 -163
- package/package.json +22 -17
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# DatePicker
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|
-
|
|
54
|
+
## Sizes
|
|
69
55
|
|
|
70
|
-
DatePicker supports three sizes
|
|
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
|
-
|
|
66
|
+
## Label and Helper Text
|
|
81
67
|
|
|
82
|
-
|
|
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
|
-
|
|
85
|
+
## Validation and Error State
|
|
104
86
|
|
|
105
|
-
|
|
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
|
-
|
|
107
|
+
## Disabled and Read-Only States
|
|
130
108
|
|
|
131
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
129
|
+
value="2024/04/01"
|
|
130
|
+
inputReadOnly
|
|
148
131
|
/>
|
|
149
132
|
```
|
|
150
133
|
|
|
151
|
-
|
|
134
|
+
## Date Restrictions
|
|
152
135
|
|
|
153
|
-
Restrict
|
|
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
|
-
|
|
141
|
+
minDate="2024-04-10"
|
|
159
142
|
/>
|
|
160
143
|
```
|
|
161
144
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
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
|
-
|
|
174
|
+
## Controlled vs Uncontrolled
|
|
185
175
|
|
|
186
|
-
|
|
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
|
-
|
|
203
|
+
## Format and Display Format
|
|
218
204
|
|
|
219
|
-
|
|
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
|
-
|
|
247
|
+
**Supported format tokens:**
|
|
266
248
|
|
|
267
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
###
|
|
259
|
+
### Reset Button
|
|
278
260
|
|
|
279
|
-
|
|
261
|
+
Pair DatePicker with an external reset button to programmatically clear the value.
|
|
280
262
|
|
|
281
263
|
```tsx
|
|
282
|
-
<
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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
|
|
355
|
+
helperText="Weekdays only"
|
|
442
356
|
/>
|
|
443
357
|
);
|
|
444
358
|
}
|
|
445
359
|
```
|
|
446
360
|
|
|
447
|
-
###
|
|
361
|
+
### Locale-Aware Display
|
|
448
362
|
|
|
449
363
|
```tsx
|
|
450
|
-
function
|
|
364
|
+
function RegionalDateField({ locale }: { locale: string }) {
|
|
451
365
|
const [date, setDate] = useState('');
|
|
452
366
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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"
|
|
473
|
-
displayFormat={
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
649
|
-
|
|
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
|
-
|
|
395
|
+
2. **Keep value format consistent with the `format` prop**
|
|
657
396
|
|
|
658
397
|
```tsx
|
|
659
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
702
|
-
<DatePicker
|
|
418
|
+
{/* Do */}
|
|
419
|
+
<DatePicker label="Birth Date" disableFuture minDate="1900/01/01" />
|
|
703
420
|
|
|
704
|
-
|
|
421
|
+
{/* Don't -- unrestricted date range for a birth date field */}
|
|
705
422
|
<DatePicker label="Birth Date" />
|
|
706
423
|
```
|
|
707
424
|
|
|
708
|
-
|
|
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
|
-
|
|
716
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|