@ceed/cds 1.29.0 → 1.30.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 (62) hide show
  1. package/dist/Overview.md +5 -5
  2. package/dist/components/Calendar/utils/index.d.ts +1 -0
  3. package/dist/components/DatePicker/DatePicker.d.ts +4 -0
  4. package/dist/components/DateRangePicker/DateRangePicker.d.ts +4 -0
  5. package/dist/components/MonthRangePicker/MonthRangePicker.d.ts +8 -0
  6. package/dist/components/data-display/Avatar.md +110 -69
  7. package/dist/components/data-display/Badge.md +91 -39
  8. package/dist/components/data-display/Chip.md +49 -20
  9. package/dist/components/data-display/DataTable.md +93 -0
  10. package/dist/components/data-display/InfoSign.md +12 -0
  11. package/dist/components/data-display/Table.md +72 -55
  12. package/dist/components/data-display/Tooltip.md +40 -40
  13. package/dist/components/data-display/Typography.md +53 -70
  14. package/dist/components/feedback/Alert.md +88 -72
  15. package/dist/components/feedback/CircularProgress.md +17 -0
  16. package/dist/components/feedback/Skeleton.md +17 -0
  17. package/dist/components/inputs/Button.md +94 -68
  18. package/dist/components/inputs/ButtonGroup.md +17 -0
  19. package/dist/components/inputs/Calendar.md +118 -457
  20. package/dist/components/inputs/Checkbox.md +185 -430
  21. package/dist/components/inputs/CurrencyInput.md +22 -0
  22. package/dist/components/inputs/DatePicker.md +59 -5
  23. package/dist/components/inputs/DateRangePicker.md +46 -5
  24. package/dist/components/inputs/FilterableCheckboxGroup.md +20 -3
  25. package/dist/components/inputs/FormControl.md +32 -2
  26. package/dist/components/inputs/IconButton.md +18 -0
  27. package/dist/components/inputs/Input.md +198 -136
  28. package/dist/components/inputs/MonthPicker.md +59 -5
  29. package/dist/components/inputs/MonthRangePicker.md +44 -5
  30. package/dist/components/inputs/PercentageInput.md +25 -0
  31. package/dist/components/inputs/RadioButton.md +23 -0
  32. package/dist/components/inputs/RadioList.md +20 -1
  33. package/dist/components/inputs/RadioTileGroup.md +37 -3
  34. package/dist/components/inputs/Select.md +56 -0
  35. package/dist/components/inputs/Slider.md +23 -0
  36. package/dist/components/inputs/Switch.md +20 -0
  37. package/dist/components/inputs/Textarea.md +32 -8
  38. package/dist/components/inputs/Uploader/Uploader.md +21 -0
  39. package/dist/components/layout/Box.md +52 -41
  40. package/dist/components/layout/Grid.md +87 -81
  41. package/dist/components/layout/Stack.md +88 -68
  42. package/dist/components/navigation/Breadcrumbs.md +57 -46
  43. package/dist/components/navigation/Drawer.md +17 -0
  44. package/dist/components/navigation/Dropdown.md +13 -0
  45. package/dist/components/navigation/IconMenuButton.md +17 -0
  46. package/dist/components/navigation/InsetDrawer.md +130 -292
  47. package/dist/components/navigation/Link.md +78 -0
  48. package/dist/components/navigation/Menu.md +17 -0
  49. package/dist/components/navigation/MenuButton.md +18 -0
  50. package/dist/components/navigation/Pagination.md +13 -0
  51. package/dist/components/navigation/Stepper.md +15 -0
  52. package/dist/components/navigation/Tabs.md +27 -0
  53. package/dist/components/surfaces/Accordions.md +804 -49
  54. package/dist/components/surfaces/Card.md +173 -97
  55. package/dist/components/surfaces/Divider.md +246 -82
  56. package/dist/components/surfaces/Sheet.md +15 -0
  57. package/dist/index.browser.js +4 -4
  58. package/dist/index.browser.js.map +3 -3
  59. package/dist/index.cjs +99 -39
  60. package/dist/index.js +99 -39
  61. package/framer/index.js +1 -1
  62. package/package.json +1 -1
@@ -2,9 +2,7 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- The Input component is a fundamental form element for capturing text input from users. It supports various visual styles, sizes, and states to accommodate different use cases across forms, search fields, and data entry interfaces.
6
-
7
- Input comes with built-in form integration features such as labels, helper text, error states, and clearable functionality. It also provides specialized behavior for password fields with an automatic visibility toggle.
5
+ Input is a single-line text field component for capturing user input. Built on Joy UI's Input with Framer Motion animation support, it includes built-in form field composition (`label`, `helperText`, `error`) so you can build complete form fields without manual `FormControl` wrappers. It supports clearable inputs, password visibility toggling, and start/end decorators.
8
6
 
9
7
  ```tsx
10
8
  <Input />
@@ -35,20 +33,8 @@ Input comes with built-in form integration features such as labels, helper text,
35
33
 
36
34
  > **Use built-in form props**
37
35
  >
38
- > This component natively supports `label`, `helperText`, `error`, and `required` props.
39
- > When building forms, use these built-in props instead of manually composing labels and helper text with Typography or FormControl.
40
- >
41
- > ```tsx
42
- > // Recommended: use built-in props
43
- > <Input label="Email" helperText="We'll never share your email." error={!isValid} />
44
- >
45
- > // Not recommended: manual composition with Typography
46
- > <FormControl>
47
- > <Typography component="label">Email</Typography>
48
- > <Input />
49
- > <Typography level="body-xs">We'll never share your email.</Typography>
50
- > </FormControl>
51
- > ```
36
+ > This component natively supports `label` and `helperText` props.
37
+ > When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
52
38
 
53
39
  ## Usage
54
40
 
@@ -56,29 +42,22 @@ Input comes with built-in form integration features such as labels, helper text,
56
42
  import { Input } from '@ceed/cds';
57
43
 
58
44
  function MyComponent() {
45
+ const [value, setValue] = useState('');
46
+
59
47
  return (
60
48
  <Input
61
- label="Username"
62
- placeholder="Enter your username"
63
- helperText="Must be at least 3 characters"
49
+ label="Name"
50
+ placeholder="Enter your name"
51
+ value={value}
52
+ onChange={(e) => setValue(e.target.value)}
64
53
  />
65
54
  );
66
55
  }
67
56
  ```
68
57
 
69
- ## Examples
70
-
71
- ### Basic Input
72
-
73
- The default Input renders a single-line text field. Without any additional props, it uses the `outlined` variant at `md` size.
74
-
75
- ```tsx
76
- <Input />
77
- ```
78
-
79
- ### Variants
58
+ ## Variants
80
59
 
81
- Input supports four visual variants: `solid`, `soft`, `outlined`, and `plain`. Use `outlined` (default) for most form contexts, and `soft` or `plain` for inline or subtle placements.
60
+ Input supports four visual styles: `outlined` (default), `solid`, `soft`, and `plain`.
82
61
 
83
62
  ```tsx
84
63
  <>
@@ -89,9 +68,9 @@ Input supports four visual variants: `solid`, `soft`, `outlined`, and `plain`. U
89
68
  </>
90
69
  ```
91
70
 
92
- ### Sizes
71
+ ## Sizes
93
72
 
94
- Input comes in three sizes: `sm`, `md`, and `lg`. Choose a size that fits the surrounding UI density.
73
+ Three sizes are available: `sm`, `md` (default), and `lg`.
95
74
 
96
75
  ```tsx
97
76
  <>
@@ -105,7 +84,7 @@ Input comes in three sizes: `sm`, `md`, and `lg`. Choose a size that fits the su
105
84
 
106
85
  ### Label
107
86
 
108
- Use the `label` prop to display a label above the Input. This is the recommended way to associate a label with the input field.
87
+ The `label` prop renders a form label above the input.
109
88
 
110
89
  ```tsx
111
90
  <>
@@ -115,7 +94,7 @@ Use the `label` prop to display a label above the Input. This is the recommended
115
94
 
116
95
  ### Helper Text
117
96
 
118
- Use the `helperText` prop to provide additional guidance below the Input.
97
+ The `helperText` prop renders descriptive text below the input.
119
98
 
120
99
  ```tsx
121
100
  <>
@@ -127,7 +106,7 @@ Use the `helperText` prop to provide additional guidance below the Input.
127
106
 
128
107
  ### Disabled
129
108
 
130
- Set `disabled` to prevent user interaction. Disabled inputs are visually dimmed and do not receive focus.
109
+ A disabled input cannot be focused or interacted with.
131
110
 
132
111
  ```tsx
133
112
  <Input disabled />
@@ -135,7 +114,7 @@ Set `disabled` to prevent user interaction. Disabled inputs are visually dimmed
135
114
 
136
115
  ### Error
137
116
 
138
- Set `error` to indicate a validation failure. Combine with `helperText` to explain the error.
117
+ Set `error` to visually indicate a validation failure. Combine with `helperText` to display an error message.
139
118
 
140
119
  ```tsx
141
120
  <>
@@ -145,7 +124,7 @@ Set `error` to indicate a validation failure. Combine with `helperText` to expla
145
124
 
146
125
  ### Required
147
126
 
148
- Set `required` to mark the field as mandatory. This adds a visual indicator to the label.
127
+ Set `required` to mark the field as required. An asterisk is added to the label automatically.
149
128
 
150
129
  ```tsx
151
130
  <Input
@@ -156,20 +135,9 @@ Set `required` to mark the field as mandatory. This adds a visual indicator to t
156
135
  />
157
136
  ```
158
137
 
159
- ## Form Control
160
-
161
- Combine `label`, `helperText`, and `error` props to build a complete form control. This is the recommended pattern for form fields.
162
-
163
- ```tsx
164
- <>
165
- <Input placeholder="Type in here..." helperText="I'm helper text" label="Label" />
166
- <Input placeholder="Invalid input" helperText="I'm helper text" label="Label" error />
167
- </>
168
- ```
169
-
170
138
  ## Decorators
171
139
 
172
- Use `startDecorator` and `endDecorator` to place icons, buttons, or other elements at the start and end of the input field.
140
+ Use `startDecorator` and `endDecorator` to add icons, buttons, or other elements at the start or end of the input field.
173
141
 
174
142
  ```tsx
175
143
  <Stack spacing={3}>
@@ -209,7 +177,7 @@ width: 300
209
177
  </Stack>
210
178
  ```
211
179
 
212
- When using `endDecorator` together with `enableClearable`, the clear button is placed before the end decorator:
180
+ When using `endDecorator` together with `enableClearable`, both elements are displayed side by side:
213
181
 
214
182
  ```tsx
215
183
  <Input
@@ -222,7 +190,7 @@ When using `endDecorator` together with `enableClearable`, the clear button is p
222
190
 
223
191
  ## Clearable Input
224
192
 
225
- Set `enableClearable` to show a clear button when the input has a value. Clicking the button clears the input and returns focus to the field.
193
+ Set `enableClearable` to show a clear button when the input has a value. Clicking the button clears the input content.
226
194
 
227
195
  ```tsx
228
196
  <>
@@ -230,9 +198,16 @@ Set `enableClearable` to show a clear button when the input has a value. Clickin
230
198
  </>
231
199
  ```
232
200
 
201
+ ```tsx
202
+ <Input
203
+ enableClearable
204
+ placeholder="Type something and clear it"
205
+ />
206
+ ```
207
+
233
208
  ## Password Input
234
209
 
235
- Setting `type="password"` automatically adds a visibility toggle button, allowing users to reveal or hide their password.
210
+ Setting `type="password"` creates a password field with an automatic visibility toggle button.
236
211
 
237
212
  ```tsx
238
213
  <Stack spacing={3}>
@@ -247,9 +222,17 @@ Setting `type="password"` automatically adds a visibility toggle button, allowin
247
222
  </Stack>
248
223
  ```
249
224
 
250
- ### Password Limitations
225
+ ### Disabling the Password Toggle
251
226
 
252
- When `type="password"` is used, the `endDecorator` prop is not supported because the password toggle button occupies that position.
227
+ Use `disableTogglePasswordButton` to hide the visibility toggle button on password inputs.
228
+
229
+ ```tsx
230
+ <Input type="password" disableTogglePasswordButton placeholder="Password" />
231
+ ```
232
+
233
+ ### Password Input Limitations
234
+
235
+ Password inputs (`type="password"`) do not support custom `endDecorator` because the password toggle button occupies that slot. If you provide `endDecorator` with a password input, the component logs a warning and ignores it.
253
236
 
254
237
  ```tsx
255
238
  <Stack spacing={3}>
@@ -261,62 +244,69 @@ When `type="password"` is used, the `endDecorator` prop is not supported because
261
244
  </Stack>
262
245
  ```
263
246
 
264
- ## State Management
265
-
266
- ### Controlled Component
247
+ ## Form Control
267
248
 
268
- Use `value` and `onChange` to manage the input state externally. This is useful when you need to synchronize the value with other components or perform validation on change.
249
+ Combining `label`, `helperText`, and `error` produces a complete form field.
269
250
 
270
251
  ```tsx
271
252
  <>
272
- <Input placeholder="Type in here" label="Label" enableClearable value={value} onChange={handleChange} />
253
+ <Input placeholder="Type in here..." helperText="I'm helper text" label="Label" />
254
+ <Input placeholder="Invalid input" helperText="I'm helper text" label="Label" error />
273
255
  </>
274
256
  ```
275
257
 
276
- ### Uncontrolled Component
258
+ ```tsx
259
+ <Input
260
+ label="Email"
261
+ helperText="We'll never share your email"
262
+ required
263
+ />
264
+
265
+ <Input
266
+ label="Email"
267
+ error
268
+ helperText="Invalid email address"
269
+ />
270
+ ```
271
+
272
+ ## Controlled / Uncontrolled
277
273
 
278
- Use `defaultValue` for simpler cases where you do not need to track the value in state. The input manages its own value internally.
274
+ ### Controlled
275
+
276
+ Use `value` and `onChange` for controlled behavior.
279
277
 
280
278
  ```tsx
281
- <Input defaultValue="Initial text" placeholder="Type in here..." />
279
+ <>
280
+ <Input placeholder="Type in here…" label="Label" enableClearable value={value} onChange={handleChange} />
281
+ </>
282
282
  ```
283
283
 
284
- ## Common Use Cases
284
+ ```tsx
285
+ const [value, setValue] = useState('');
285
286
 
286
- ### Login Form
287
+ <Input
288
+ value={value}
289
+ onChange={(e) => setValue(e.target.value)}
290
+ placeholder="Controlled input"
291
+ />
292
+ ```
287
293
 
288
- ```tsx
289
- function LoginForm() {
290
- const [email, setEmail] = useState('');
291
- const [password, setPassword] = useState('');
294
+ ### Uncontrolled
292
295
 
293
- return (
294
- <Stack spacing={2}>
295
- <Input
296
- label="Email"
297
- type="email"
298
- placeholder="you@example.com"
299
- required
300
- value={email}
301
- onChange={(e) => setEmail(e.target.value)}
302
- />
303
- <Input
304
- label="Password"
305
- type="password"
306
- placeholder="Enter your password"
307
- required
308
- value={password}
309
- onChange={(e) => setPassword(e.target.value)}
310
- />
311
- <Button type="submit">Sign In</Button>
312
- </Stack>
313
- );
314
- }
296
+ Use `defaultValue` for uncontrolled behavior.
297
+
298
+ ```tsx
299
+ <Input defaultValue="Initial value" placeholder="Uncontrolled input" />
315
300
  ```
316
301
 
317
- ### Search Field with Clear
302
+ ## Common Use Cases
303
+
304
+ ### Search Field
318
305
 
319
306
  ```tsx
307
+ import { Input } from '@ceed/cds';
308
+ import SearchIcon from '@mui/icons-material/Search';
309
+
320
310
  function SearchField({ onSearch }) {
321
311
  const [query, setQuery] = useState('');
322
312
 
@@ -335,80 +325,152 @@ function SearchField({ onSearch }) {
335
325
  }
336
326
  ```
337
327
 
328
+ ### Login Form
329
+
330
+ ```tsx
331
+ import { Input, Button, Stack } from '@ceed/cds';
332
+
333
+ function LoginForm({ onSubmit }) {
334
+ return (
335
+ <form onSubmit={onSubmit}>
336
+ <Stack spacing={2}>
337
+ <Input
338
+ label="Email"
339
+ type="email"
340
+ required
341
+ placeholder="Enter your email"
342
+ />
343
+ <Input
344
+ label="Password"
345
+ type="password"
346
+ required
347
+ placeholder="Enter your password"
348
+ />
349
+ <Button type="submit">Sign In</Button>
350
+ </Stack>
351
+ </form>
352
+ );
353
+ }
354
+ ```
355
+
338
356
  ### Form with Validation
339
357
 
340
358
  ```tsx
341
- function ProfileForm() {
342
- const [name, setName] = useState('');
359
+ import { useState } from 'react';
360
+ import { Input, Button, Stack } from '@ceed/cds';
361
+
362
+ function ValidatedForm() {
363
+ const [email, setEmail] = useState('');
343
364
  const [submitted, setSubmitted] = useState(false);
344
- const hasError = submitted && name.trim().length === 0;
365
+ const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
345
366
 
346
367
  return (
347
- <Stack spacing={2}>
348
- <Input
349
- label="Full Name"
350
- required
351
- placeholder="John Doe"
352
- value={name}
353
- onChange={(e) => setName(e.target.value)}
354
- error={hasError}
355
- helperText={hasError ? 'Name is required' : 'Enter your legal name'}
356
- />
357
- <Button onClick={() => setSubmitted(true)}>Save</Button>
358
- </Stack>
368
+ <form onSubmit={(e) => { e.preventDefault(); setSubmitted(true); }}>
369
+ <Stack spacing={2}>
370
+ <Input
371
+ label="Email"
372
+ required
373
+ value={email}
374
+ onChange={(e) => setEmail(e.target.value)}
375
+ error={submitted && !isValid}
376
+ helperText={submitted && !isValid ? 'Please enter a valid email' : undefined}
377
+ placeholder="user@example.com"
378
+ />
379
+ <Button type="submit">Submit</Button>
380
+ </Stack>
381
+ </form>
359
382
  );
360
383
  }
361
384
  ```
362
385
 
386
+ ## Props and Customization
387
+
388
+ ### Key Props
389
+
390
+ | Prop | Type | Default | Description |
391
+ | ----------------------------- | -------------------------------------------------------------- | ------------ | ------------------------------------------------------------------------------- |
392
+ | `label` | `ReactNode` | - | Label text displayed above the input |
393
+ | `helperText` | `ReactNode` | - | Helper text displayed below the input |
394
+ | `error` | `boolean` | `false` | Applies danger color to indicate validation error |
395
+ | `enableClearable` | `boolean` | `false` | Shows a clear button when the input has a value |
396
+ | `disableTogglePasswordButton` | `boolean` | `false` | Hides the password visibility toggle (only applies when `type="password"`) |
397
+ | `value` | `string` | - | Input value for controlled mode |
398
+ | `defaultValue` | `string` | - | Initial value for uncontrolled mode |
399
+ | `onChange` | `(event: ChangeEvent<HTMLInputElement>) => void` | - | Callback when the input value changes |
400
+ | `placeholder` | `string` | - | Placeholder text when the input is empty |
401
+ | `type` | `string` | `'text'` | HTML input type (`text`, `password`, `email`, `number`, etc.) |
402
+ | `disabled` | `boolean` | `false` | Disables the input |
403
+ | `readOnly` | `boolean` | `false` | Makes the input read-only (focusable but not editable) |
404
+ | `required` | `boolean` | `false` | Marks the field as required (adds asterisk to label) |
405
+ | `name` | `string` | - | HTML name attribute for form submission |
406
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Input size |
407
+ | `variant` | `'outlined' \| 'solid' \| 'soft' \| 'plain'` | `'outlined'` | Visual style variant |
408
+ | `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | `'neutral'` | Color scheme |
409
+ | `startDecorator` | `ReactNode` | - | Content rendered at the start of the input |
410
+ | `endDecorator` | `ReactNode` | - | Content rendered at the end of the input (not supported with `type="password"`) |
411
+ | `sx` | `SxProps` | - | Custom styles using the MUI system |
412
+
413
+ > **Note**: Input also accepts all Joy UI Input props and Framer Motion props.
414
+
363
415
  ## Best Practices
364
416
 
365
- 1. **Always provide a label**: Every input should have a visible label so users understand what to enter.
417
+ 1. **Use built-in `label` and `helperText`** instead of wrapping with FormControl manually.
366
418
 
367
419
  ```tsx
368
- // ✅ Good: clear label
369
- <Input label="Email address" placeholder="you@example.com" />
370
-
371
- // ❌ Bad: placeholder only, no label
372
- <Input placeholder="Email address" />
420
+ // ✅ Good
421
+ <Input label="Email" helperText="Enter your work email" />
422
+
423
+ // ❌ Bad
424
+ <FormControl>
425
+ <FormLabel>Email</FormLabel>
426
+ <Input />
427
+ <FormHelperText>Enter your work email</FormHelperText>
428
+ </FormControl>
373
429
  ```
374
430
 
375
- 2. **Use helper text for guidance, error text for problems**: Provide contextual help via `helperText`, and switch to error messaging when validation fails.
431
+ 2. **Choose the right input type** for the data being captured.
376
432
 
377
433
  ```tsx
378
- // ✅ Good: helpful context + error state
379
- <Input
380
- label="Password"
381
- type="password"
382
- helperText={hasError ? 'Must be at least 8 characters' : 'Choose a strong password'}
383
- error={hasError}
384
- />
434
+ // ✅ Good: Appropriate types
435
+ <Input type="email" label="Email" />
436
+ <Input type="password" label="Password" />
437
+ <Input type="tel" label="Phone" />
385
438
 
386
- // ❌ Bad: no guidance at all
387
- <Input label="Password" type="password" />
439
+ // ❌ Bad: Generic text for everything
440
+ <Input type="text" label="Email" />
388
441
  ```
389
442
 
390
- 3. **Choose the right input type**: Use `type` to match the expected data (e.g., `email`, `tel`, `password`, `number`). This enables appropriate browser behavior and mobile keyboards.
443
+ 3. **Always provide labels** for accessibility. If a visible label is not appropriate, use `aria-label`.
391
444
 
392
445
  ```tsx
393
- // ✅ Good: appropriate type for email
394
- <Input label="Email" type="email" />
446
+ // ✅ Good: Visible label
447
+ <Input label="Search" />
448
+
449
+ // ✅ Good: Hidden label for icon-only inputs
450
+ <Input aria-label="Search" startDecorator={<SearchIcon />} />
395
451
 
396
- // ❌ Bad: generic text type for email
397
- <Input label="Email" type="text" />
452
+ // ❌ Bad: No label at all
453
+ <Input placeholder="Search..." />
398
454
  ```
399
455
 
400
- 4. **Use `enableClearable` for search and filter inputs**: Allow users to quickly reset their input in search and filter contexts.
456
+ 4. **Use `enableClearable` for search and filter inputs** where users frequently need to clear and re-enter values.
401
457
 
402
- 5. **Use built-in form props instead of manual composition**: Prefer `label`, `helperText`, `error`, and `required` props over wrapping with FormControl and Typography. This ensures consistent spacing, accessibility, and error handling.
458
+ 5. **Do not use `endDecorator` with password inputs.** The password toggle button occupies the end slot. Use `startDecorator` instead for additional icons.
403
459
 
404
460
  ## Accessibility
405
461
 
406
- - **Label association**: The `label` prop automatically creates a properly associated `<label>` element. If you cannot use the `label` prop, provide an `aria-label` or `aria-labelledby` attribute.
407
- - **Error announcement**: When `error` is set, the error state is conveyed to assistive technologies via `aria-invalid`. Combine with descriptive `helperText` so screen readers can announce the error message.
408
- - **Keyboard interaction**: Input supports standard keyboard behavior. The clear button and password toggle are focusable and can be activated with Enter or Space.
409
- - **Testing note**: When using Testing Library, find a `type="password"` input using the `textbox` role, as ARIA does not define a separate `password` role.
462
+ - **Label association**: The `label` prop automatically connects the label to the input via `htmlFor`/`id` pairing.
463
+ - **Keyboard navigation**: Standard keyboard support Tab to focus, type to input, Escape to blur (when applicable).
464
+ - **Error announcement**: When `error` is set, `aria-invalid` is applied. Pair with `helperText` so assistive technology announces the error.
465
+ - **Required state**: The `required` prop adds `aria-required` and a visible asterisk to the label.
466
+ - **Password toggle**: The visibility toggle button is keyboard-accessible and includes an appropriate `aria-label`.
467
+
468
+ ## Testing Notes
469
+
470
+ When using Testing Library, always query password inputs by `textbox` role:
410
471
 
411
472
  ```tsx
412
- // Finding a password input in tests
413
473
  const passwordInput = screen.getByRole('textbox', { name: /password/i });
414
474
  ```
475
+
476
+ This is because the ARIA specification does not define a `password` role — password inputs use the default `textbox` role.
@@ -229,6 +229,18 @@ The `displayFormat` prop controls what users see in the input field, independent
229
229
  setValue6(e.target.value);
230
230
  args.onChange?.(e);
231
231
  }} />
232
+ <MonthPicker {...args} value={value6} label="MMM YYYY" name="MMM YYYY" displayFormat="MMM YYYY" onChange={e => {
233
+ setValue6(e.target.value);
234
+ args.onChange?.(e);
235
+ }} />
236
+ <MonthPicker {...args} value={value6} label="MMM YYYY (en-US)" name="MMM YYYY (en-US)" displayFormat="MMM YYYY" locale="en-US" onChange={e => {
237
+ setValue6(e.target.value);
238
+ args.onChange?.(e);
239
+ }} />
240
+ <MonthPicker {...args} value={value6} label="MMM YYYY (ko-KR)" name="MMM YYYY (ko-KR)" displayFormat="MMM YYYY" locale="ko-KR" onChange={e => {
241
+ setValue6(e.target.value);
242
+ args.onChange?.(e);
243
+ }} />
232
244
  </Stack>
233
245
  ```
234
246
 
@@ -248,9 +260,7 @@ A controlled example with an external reset button to clear the selected value.
248
260
  </div>
249
261
  ```
250
262
 
251
- ## Common Use Cases
252
-
253
- ### Billing Period Selection
263
+ ## Billing Period Selection
254
264
 
255
265
  ```tsx
256
266
  function BillingPeriodSelector() {
@@ -268,7 +278,7 @@ function BillingPeriodSelector() {
268
278
  }
269
279
  ```
270
280
 
271
- ### Report Month Filter with Display Format
281
+ ## Report Month Filter with Display Format
272
282
 
273
283
  ```tsx
274
284
  function ReportFilter() {
@@ -286,7 +296,7 @@ function ReportFilter() {
286
296
  }
287
297
  ```
288
298
 
289
- ### Credit Card Expiry
299
+ ## Credit Card Expiry
290
300
 
291
301
  ```tsx
292
302
  function CreditCardExpiry() {
@@ -359,6 +369,50 @@ const handleChange = (e) => {
359
369
  };
360
370
  ```
361
371
 
372
+ ## Props and Customization
373
+
374
+ ### Key Props
375
+
376
+ | Prop | Type | Default | Description |
377
+ | --------------- | ------------------------------------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------- |
378
+ | `value` | `string` | - | Selected month string in `format` (controlled mode) |
379
+ | `defaultValue` | `string` | `''` | Initial month string (uncontrolled mode) |
380
+ | `onChange` | `(event: { target: { name?, value: string } }) => void` | - | Callback when the month changes |
381
+ | `format` | `string` | `'YYYY/MM/DD'` | Format of the `value` and `onChange` value |
382
+ | `displayFormat` | `string` | `'YYYY/MM'` | Format displayed in the input field. Supports `MMM` (short month name) and `MMMM` (full month name) tokens |
383
+ | `label` | `ReactNode` | - | Form label displayed above the input |
384
+ | `helperText` | `ReactNode` | - | Helper text displayed below the input |
385
+ | `error` | `boolean` | `false` | Applies danger color to indicate validation error |
386
+ | `required` | `boolean` | `false` | Marks the field as required |
387
+ | `disabled` | `boolean` | `false` | Disables the entire component |
388
+ | `name` | `string` | - | HTML name attribute for form submission |
389
+ | `minDate` | `string` | - | Minimum selectable month (in `format`) |
390
+ | `maxDate` | `string` | - | Maximum selectable month (in `format`) |
391
+ | `disableFuture` | `boolean` | `false` | Disables all future months |
392
+ | `disablePast` | `boolean` | `false` | Disables all past months |
393
+ | `locale` | `string` | `'default'` | Locale for month names (BCP 47 format) |
394
+
395
+ ### Alphabetic Month Tokens (MMM / MMMM)
396
+
397
+ The `displayFormat` prop supports alphabetic month tokens for more human-readable month display:
398
+
399
+ | Token | Output | Example |
400
+ | ------ | ---------------------- | ------------------------------ |
401
+ | `MMM` | Abbreviated month name | `Jan`, `Feb`, `Apr` |
402
+ | `MMMM` | Full month name | `January`, `February`, `April` |
403
+
404
+ Use the `locale` prop to control the language of month names.
405
+
406
+ ```tsx
407
+ <MonthPicker displayFormat="MMM YYYY" locale="en-US" />
408
+ // → "Apr 2026"
409
+
410
+ <MonthPicker displayFormat="MMMM YYYY" locale="ko-KR" />
411
+ // → "4월 2026"
412
+ ```
413
+
414
+ > **Note**: MonthPicker also accepts all Input props (e.g., `size`, `variant`, `color`, `sx`).
415
+
362
416
  ## Accessibility
363
417
 
364
418
  - The input has `role="textbox"` and the calendar toggle button has `aria-label="Toggle Calendar"` for screen reader identification.