@ceed/ads 1.29.0 → 1.30.0-next.1

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 (64) hide show
  1. package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
  2. package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
  3. package/dist/components/DataTable/hooks.d.ts +2 -1
  4. package/dist/components/DataTable/utils.d.ts +1 -0
  5. package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
  6. package/dist/components/SearchBar/SearchBar.d.ts +21 -0
  7. package/dist/components/SearchBar/index.d.ts +3 -0
  8. package/dist/components/data-display/Badge.md +39 -71
  9. package/dist/components/data-display/DataTable.md +1 -1
  10. package/dist/components/data-display/InfoSign.md +98 -74
  11. package/dist/components/data-display/Typography.md +97 -363
  12. package/dist/components/feedback/Dialog.md +62 -76
  13. package/dist/components/feedback/Modal.md +44 -259
  14. package/dist/components/feedback/llms.txt +0 -2
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/inputs/Autocomplete.md +107 -356
  17. package/dist/components/inputs/ButtonGroup.md +106 -115
  18. package/dist/components/inputs/Calendar.md +459 -98
  19. package/dist/components/inputs/CurrencyInput.md +5 -183
  20. package/dist/components/inputs/DatePicker.md +431 -108
  21. package/dist/components/inputs/DateRangePicker.md +492 -131
  22. package/dist/components/inputs/FilterMenu.md +19 -169
  23. package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
  24. package/dist/components/inputs/IconButton.md +88 -137
  25. package/dist/components/inputs/Input.md +0 -5
  26. package/dist/components/inputs/MonthPicker.md +422 -95
  27. package/dist/components/inputs/MonthRangePicker.md +466 -89
  28. package/dist/components/inputs/PercentageInput.md +16 -185
  29. package/dist/components/inputs/RadioButton.md +35 -163
  30. package/dist/components/inputs/RadioTileGroup.md +61 -150
  31. package/dist/components/inputs/SearchBar.md +44 -0
  32. package/dist/components/inputs/Select.md +326 -222
  33. package/dist/components/inputs/Switch.md +376 -136
  34. package/dist/components/inputs/Textarea.md +10 -213
  35. package/dist/components/inputs/Uploader/Uploader.md +66 -145
  36. package/dist/components/inputs/llms.txt +1 -3
  37. package/dist/components/navigation/Breadcrumbs.md +322 -80
  38. package/dist/components/navigation/Dropdown.md +221 -92
  39. package/dist/components/navigation/IconMenuButton.md +502 -40
  40. package/dist/components/navigation/InsetDrawer.md +738 -68
  41. package/dist/components/navigation/Link.md +298 -39
  42. package/dist/components/navigation/Menu.md +285 -92
  43. package/dist/components/navigation/MenuButton.md +448 -55
  44. package/dist/components/navigation/Pagination.md +338 -47
  45. package/dist/components/navigation/ProfileMenu.md +268 -45
  46. package/dist/components/navigation/Stepper.md +28 -160
  47. package/dist/components/navigation/Tabs.md +316 -57
  48. package/dist/components/surfaces/Sheet.md +334 -151
  49. package/dist/index.browser.js +15 -13
  50. package/dist/index.browser.js.map +4 -4
  51. package/dist/index.cjs +313 -291
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.js +450 -372
  54. package/dist/llms.txt +1 -8
  55. package/framer/index.js +1 -1
  56. package/package.json +16 -15
  57. package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
  58. package/dist/components/feedback/CircularProgress.md +0 -257
  59. package/dist/components/feedback/Skeleton.md +0 -280
  60. package/dist/components/inputs/FormControl.md +0 -361
  61. package/dist/components/inputs/RadioList.md +0 -241
  62. package/dist/components/inputs/Slider.md +0 -334
  63. package/dist/guides/ThemeProvider.md +0 -116
  64. package/dist/guides/llms.txt +0 -9
@@ -8,36 +8,10 @@ Autocomplete is an enhanced input component that provides real-time suggestions
8
8
  <Autocomplete options={['Option1', 'Option2']} />
9
9
  ```
10
10
 
11
- | Field | Description | Default |
12
- | --------------------- | ----------- | ------- |
13
- | variant | — | — |
14
- | color | — | — |
15
- | size | — | — |
16
- | placeholder | — | — |
17
- | label | — | — |
18
- | helperText | — | — |
19
- | error | — | — |
20
- | required | — | — |
21
- | disabled | — | — |
22
- | readOnly | — | — |
23
- | multiple | — | — |
24
- | freeSolo | — | — |
25
- | disableClearable | — | — |
26
- | autoHighlight | — | — |
27
- | clearOnEscape | — | — |
28
- | disableCloseOnSelect | — | — |
29
- | openOnFocus | — | — |
30
- | blurOnSelect | — | — |
31
- | filterSelectedOptions | — | — |
32
- | selectOnFocus | — | — |
33
- | clearOnBlur | — | — |
34
- | forcePopupIcon | — | — |
35
- | loading | — | — |
36
- | noOptionsText | — | — |
37
- | loadingText | — | — |
38
- | limitTags | — | — |
39
- | value | — | — |
40
- | defaultValue | — | — |
11
+ | Field | Description | Default |
12
+ | ------- | ----------- | ------- |
13
+ | label | — | — |
14
+ | loading | — | — |
41
15
 
42
16
  > ⚠️ **Usage Warning** ⚠️
43
17
  >
@@ -48,11 +22,6 @@ Autocomplete is an enhanced input component that provides real-time suggestions
48
22
  > - **Dropdown**: For action menus, not form value selection
49
23
  > - **Input**: For free-text entry without predefined options
50
24
 
51
- > 💡 **Use built-in form props**
52
- >
53
- > This component natively supports form elements such as `label` and `helperText` props.
54
- > When building forms, use these built-in props instead of manually composing labels and helper text with Typography.
55
-
56
25
  ## Usage
57
26
 
58
27
  ```tsx
@@ -73,136 +42,23 @@ function CountrySelector() {
73
42
  }
74
43
  ```
75
44
 
76
- ## Variants
77
-
78
- The `variant` prop controls the visual style of the autocomplete input. Available variants: `outlined` (default), `soft`, `solid`, `plain`.
79
-
80
- ```tsx
81
- <Stack gap={2} p={2}>
82
- {variants.map(variant => <Autocomplete key={variant} variant={variant} options={sampleOptions} placeholder={variant} label={variant} sx={{
83
- maxWidth: 300
84
- }} />)}
85
- </Stack>
86
- ```
87
-
88
- ## Sizes
89
-
90
- Available size options: `sm`, `md`, `lg`.
91
-
92
- ```tsx
93
- <div style={{
94
- display: 'flex',
95
- gap: '10px'
96
- }}>
97
- <Autocomplete {...args} size="sm" />
98
- <Autocomplete {...args} size="md" />
99
- <Autocomplete {...args} size="lg" />
100
- </div>
101
- ```
102
-
103
- ## Colors
104
-
105
- The `color` prop changes the color scheme. Available colors: `primary`, `neutral`, `danger`, `success`, `warning`.
106
-
107
- ```tsx
108
- <Stack gap={2} p={2}>
109
- {colors.map(color => <Autocomplete key={color} color={color} options={sampleOptions} defaultValue="Apple" label={color} sx={{
110
- maxWidth: 300
111
- }} />)}
112
- </Stack>
113
- ```
114
-
115
- ## States
116
-
117
- Autocomplete supports several form states for different interaction contexts.
118
-
119
- ### Disabled
120
-
121
- A disabled autocomplete cannot be focused or interacted with. Use for fields that are temporarily unavailable.
122
-
123
- ### Read Only
124
-
125
- A read-only autocomplete can be focused and its value copied, but cannot be changed. Use when a value should be visible but not editable.
126
-
127
- ### Error
128
-
129
- Set `error` along with `helperText` to indicate validation failures.
130
-
131
- ### Required
132
-
133
- Set `required` to mark the field as required in a form.
134
-
135
- ```tsx
136
- <Stack gap={3} p={2} sx={{
137
- maxWidth: 300
138
- }}>
139
- <Autocomplete label="Disabled" options={sampleOptions} defaultValue="Apple" disabled />
140
- <Autocomplete label="Read Only" options={sampleOptions} defaultValue="Banana" readOnly />
141
- <Autocomplete label="Error" options={sampleOptions} error helperText="This field is required" />
142
- <Autocomplete label="Required" options={sampleOptions} required placeholder="Select a fruit..." />
143
- </Stack>
144
- ```
145
-
146
- ## Free Solo
147
-
148
- The `freeSolo` prop allows users to type arbitrary values that are not in the options list. This is useful for inputs where the user can either pick a suggestion or enter a custom value.
149
-
150
- > ⚠️ **Known limitation**: The component's internal `handleChange` accesses `newValue.value`, which is `undefined` for raw strings in freeSolo mode. Typed arbitrary values may not propagate correctly through `onChange`. Consider using `onInputChange` as an alternative for capturing free-text input.
151
-
152
- ```tsx
153
- <Stack gap={2} p={2} sx={{
154
- maxWidth: 300
155
- }}>
156
- <Autocomplete label="Free Solo" options={sampleOptions} freeSolo placeholder="Type anything..." value={value} onChange={e => setValue(e.target.value)} />
157
- <Typography level="body-sm" textColor="text.tertiary">
158
- Current value: {value ?? '(empty)'}
159
- </Typography>
160
- <Typography level="body-xs" textColor="text.tertiary">
161
- Note: freeSolo allows arbitrary text input. However, the component&apos;s onChange handler accesses
162
- newValue.value which is undefined for raw strings, so typed values may not propagate correctly.
163
- </Typography>
164
- </Stack>
165
- ```
166
-
167
- ## Disable Clearable
168
-
169
- Set `disableClearable` to hide the clear (X) button. This forces the user to always have a selection.
170
-
171
- ```tsx
172
- <Autocomplete
173
- options={sampleOptions}
174
- defaultValue="Cherry"
175
- disableClearable
176
- label="Disable Clearable"
177
- sx={{
178
- maxWidth: 300
179
- }}
180
- />
181
- ```
45
+ ## Examples
182
46
 
183
- ## Custom Texts
47
+ ### Playground
184
48
 
185
- Customize the messages shown when there are no matching options or while loading.
49
+ Interactive example with basic string options.
186
50
 
187
51
  ```tsx
188
- <Stack gap={3} direction="row" p={2}>
189
- <Autocomplete label="Custom No Options Text" options={[]} noOptionsText="No fruits found — try a different search" placeholder="Search fruits..." sx={{
190
- minWidth: 280
191
- }} />
192
- <Autocomplete label="Custom Loading Text" options={[]} loading loadingText="Fetching fruits from the orchard..." placeholder="Loading fruits..." sx={{
193
- minWidth: 280
194
- }} />
195
- </Stack>
52
+ <Autocomplete options={['Option1', 'Option2']} />
196
53
  ```
197
54
 
198
- ## Multiple Selection
55
+ ### Sizes
199
56
 
200
- Enable `multiple` to allow selecting more than one option. Selected values are shown as chips.
57
+ Available size options: `sm`, `md`, `lg`.
201
58
 
202
59
  ```tsx
203
60
  <div style={{
204
61
  display: 'flex',
205
- flexDirection: 'column',
206
62
  gap: '10px'
207
63
  }}>
208
64
  <Autocomplete {...args} size="sm" />
@@ -211,28 +67,7 @@ Enable `multiple` to allow selecting more than one option. Selected values are s
211
67
  </div>
212
68
  ```
213
69
 
214
- ### Limit Tags
215
-
216
- In multiple mode, use `limitTags` to control how many tags are visible before truncating. Use `filterSelectedOptions` to hide already-selected options from the dropdown.
217
-
218
- > 💡 The component uses a custom `renderTags` implementation. JoyUI's `limitTags` truncates the array passed to `renderTags`, so tags will be limited, but the default "+N more" indicator text may not appear.
219
-
220
- ```tsx
221
- <Stack gap={3} p={2} sx={{
222
- maxWidth: 400
223
- }}>
224
- <Stack gap={1}>
225
- <Typography level="title-sm">limitTags=2</Typography>
226
- <Autocomplete multiple options={sampleOptions} defaultValue={['Apple', 'Banana', 'Cherry', 'Date']} limitTags={2} label="Limit Tags" />
227
- </Stack>
228
- <Stack gap={1}>
229
- <Typography level="title-sm">filterSelectedOptions</Typography>
230
- <Autocomplete multiple options={sampleOptions} defaultValue={['Apple', 'Banana']} filterSelectedOptions label="Filter Selected Options" />
231
- </Stack>
232
- </Stack>
233
- ```
234
-
235
- ## Option Groups
70
+ ### Option Groups
236
71
 
237
72
  Group options into categories using the `groupBy` function.
238
73
 
@@ -260,7 +95,7 @@ Group options into categories using the `groupBy` function.
260
95
  />
261
96
  ```
262
97
 
263
- ## Custom Options
98
+ ### Custom Options
264
99
 
265
100
  Options can include decorators for rich content display.
266
101
 
@@ -281,28 +116,7 @@ Options can include decorators for rich content display.
281
116
  />
282
117
  ```
283
118
 
284
- ## Secondary Text
285
-
286
- Options can display a secondary line of text using the `secondaryText` property. This is useful for showing additional context like emails, phone numbers, or descriptions alongside the main label.
287
-
288
- ```tsx
289
- <Stack gap={4} direction="row" alignItems="flex-start" p={2}>
290
- {sizes.map(size => <Stack key={size} gap={1}>
291
- <span style={{
292
- color: '#6366f1',
293
- fontSize: 12
294
- }}>{size}</span>
295
- <Autocomplete placeholder="Placeholder" options={optionsWithSecondaryText} value={values[size]} onChange={e => setValues(prev => ({
296
- ...prev,
297
- [size]: e.target.value
298
- }))} sx={{
299
- minWidth: 200
300
- }} size={size} />
301
- </Stack>)}
302
- </Stack>
303
- ```
304
-
305
- ## Loading State
119
+ ### Loading State
306
120
 
307
121
  Show a loading indicator while fetching options.
308
122
 
@@ -313,8 +127,6 @@ Show a loading indicator while fetching options.
313
127
  />
314
128
  ```
315
129
 
316
- ## Controlled / Uncontrolled
317
-
318
130
  ### Controlled
319
131
 
320
132
  Manage value externally with controlled state.
@@ -341,67 +153,6 @@ Manage value externally with controlled state.
341
153
  </Stack>
342
154
  ```
343
155
 
344
- ### Uncontrolled
345
-
346
- Let the component manage its own state with `defaultValue`.
347
-
348
- ```tsx
349
- <Autocomplete
350
- options={['Uncontrolled', 'Controlled']}
351
- label="Component Type"
352
- defaultValue="Controlled"
353
- />
354
- ```
355
-
356
- ## Virtualization
357
-
358
- Autocomplete automatically virtualizes long option lists for performance. This example renders 1,000 options efficiently.
359
-
360
- ```tsx
361
- <Autocomplete
362
- options={(() => {
363
- const res: any[] = [];
364
- for (let i = 0; i < 1000; i++) {
365
- res.push(i);
366
- }
367
- return res;
368
- })()}
369
- />
370
- ```
371
-
372
- ## Behavior Props
373
-
374
- These boolean props fine-tune interaction behavior. Toggle them in the Controls panel below to see their effects.
375
-
376
- | Prop | Default | Effect |
377
- | ---------------------- | -------- | -------------------------------------------------------------- |
378
- | `autoHighlight` | `false` | Automatically highlights the first option when the popup opens |
379
- | `clearOnEscape` | `false` | Clears the input value when the Escape key is pressed |
380
- | `disableCloseOnSelect` | `false` | Keeps the popup open after selecting an option |
381
- | `openOnFocus` | `false` | Opens the popup when the input receives focus |
382
- | `blurOnSelect` | `false` | Blurs the input after an option is selected |
383
- | `selectOnFocus` | `false` | Selects all input text when the input is focused |
384
- | `clearOnBlur` | `true` | Clears the input text on blur if it doesn't match any option |
385
- | `forcePopupIcon` | `'auto'` | Controls whether the popup icon is always shown |
386
-
387
- ```tsx
388
- <Autocomplete
389
- options={sampleOptions}
390
- label="Behavior Props"
391
- placeholder="Toggle props in the Controls panel..."
392
- autoHighlight={false}
393
- clearOnEscape={false}
394
- disableCloseOnSelect={false}
395
- openOnFocus={false}
396
- blurOnSelect={false}
397
- selectOnFocus={false}
398
- clearOnBlur
399
- sx={{
400
- maxWidth: 400
401
- }}
402
- />
403
- ```
404
-
405
156
  ## When to Use
406
157
 
407
158
  ### ✅ Good Use Cases
@@ -476,7 +227,7 @@ function UserSearch({ onSelect }) {
476
227
  label: user.name,
477
228
  secondaryText: user.email,
478
229
  startDecorator: <Avatar src={user.avatar} size="sm" />,
479
- })),
230
+ }))
480
231
  );
481
232
  } finally {
482
233
  setLoading(false);
@@ -553,7 +304,7 @@ function AddressAutocomplete({ onAddressSelect }) {
553
304
  value: result.placeId,
554
305
  label: result.formattedAddress,
555
306
  secondaryText: result.city + ', ' + result.country,
556
- })),
307
+ }))
557
308
  );
558
309
  } finally {
559
310
  setLoading(false);
@@ -645,7 +396,13 @@ function ContactSelector() {
645
396
  { value: 'michael', label: 'Michael Chen', secondaryText: '(646) 555-0876' },
646
397
  ];
647
398
 
648
- return <Autocomplete label="Contact" placeholder="Search contacts..." options={contacts} />;
399
+ return (
400
+ <Autocomplete
401
+ label="Contact"
402
+ placeholder="Search contacts..."
403
+ options={contacts}
404
+ />
405
+ );
649
406
  }
650
407
  ```
651
408
 
@@ -686,46 +443,30 @@ function LazyAutocomplete({ fetchOptions }) {
686
443
 
687
444
  ### Key Props
688
445
 
689
- | Prop | Type | Default | Description |
690
- | ----------------------- | -------------------------------------------------------------- | -------------- | ----------------------------------------------------- |
691
- | `options` | `string[] \| OptionObject[]` | `[]` | Array of options (strings or objects) |
692
- | `value` | `string \| string[]` | - | Selected value(s) for controlled mode |
693
- | `defaultValue` | `string \| string[]` | - | Initial value for uncontrolled mode |
694
- | `onChange` | `(event: { target: { value } }) => void` | - | Callback when selection changes |
695
- | `onInputChange` | `(event: { target: { value } }) => void` | - | Callback when input text changes |
696
- | `label` | `ReactNode` | - | Label text above the input |
697
- | `placeholder` | `string` | - | Placeholder text when empty |
698
- | `loading` | `boolean` | `false` | Show loading indicator |
699
- | `multiple` | `boolean` | `false` | Allow multiple selections |
700
- | `groupBy` | `(option) => string` | - | Function to group options |
701
- | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Input size |
702
- | `variant` | `'outlined' \| 'soft' \| 'solid' \| 'plain'` | `'outlined'` | Visual style variant |
703
- | `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | `'neutral'` | Color scheme |
704
- | `disabled` | `boolean` | `false` | Disable the input |
705
- | `readOnly` | `boolean` | `false` | Make the input read-only (focusable but not editable) |
706
- | `required` | `boolean` | `false` | Mark the field as required |
707
- | `error` | `boolean` | `false` | Indicate an error state |
708
- | `helperText` | `ReactNode` | - | Helper text below the input |
709
- | `freeSolo` | `boolean` | `false` | Allow arbitrary values not in the options list |
710
- | `disableClearable` | `boolean` | `false` | Hide the clear (X) button |
711
- | `noOptionsText` | `ReactNode` | `'No options'` | Text when no options match |
712
- | `loadingText` | `ReactNode` | `'Loading…'` | Text while loading |
713
- | `limitTags` | `number` | `-1` | Max visible tags in multiple mode (-1 for unlimited) |
714
- | `autoHighlight` | `boolean` | `false` | Auto-highlight first option |
715
- | `clearOnEscape` | `boolean` | `false` | Clear value on Escape key |
716
- | `disableCloseOnSelect` | `boolean` | `false` | Keep popup open after selection |
717
- | `openOnFocus` | `boolean` | `false` | Open popup on focus |
718
- | `filterSelectedOptions` | `boolean` | `false` | Hide selected options from dropdown (multiple mode) |
446
+ | Prop | Type | Default | Description |
447
+ | --------------- | ---------------------------------------- | ------- | ------------------------------------- |
448
+ | `options` | `string[] \| OptionObject[]` | `[]` | Array of options (strings or objects) |
449
+ | `value` | `string \| string[]` | - | Selected value(s) for controlled mode |
450
+ | `defaultValue` | `string \| string[]` | - | Initial value for uncontrolled mode |
451
+ | `onChange` | `(event: { target: { value } }) => void` | - | Callback when selection changes |
452
+ | `onInputChange` | `(event: { target: { value } }) => void` | - | Callback when input text changes |
453
+ | `label` | `string` | - | Label text above the input |
454
+ | `placeholder` | `string` | - | Placeholder text when empty |
455
+ | `loading` | `boolean` | `false` | Show loading indicator |
456
+ | `multiple` | `boolean` | `false` | Allow multiple selections |
457
+ | `groupBy` | `(option) => string` | - | Function to group options |
458
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Input size |
459
+ | `disabled` | `boolean` | `false` | Disable the input |
719
460
 
720
461
  ### Option Object Structure
721
462
 
722
463
  ```tsx
723
464
  interface OptionObject {
724
- value: string; // Unique value identifier
725
- label: string; // Display text
726
- secondaryText?: string; // Secondary line of text
465
+ value: string; // Unique value identifier
466
+ label: string; // Display text
467
+ secondaryText?: string; // Secondary line of text
727
468
  startDecorator?: ReactNode; // Content before label
728
- endDecorator?: ReactNode; // Content after label
469
+ endDecorator?: ReactNode; // Content after label
729
470
  }
730
471
 
731
472
  // Example option objects
@@ -750,7 +491,10 @@ const options = [
750
491
 
751
492
  ```tsx
752
493
  // Simplest usage with string array
753
- <Autocomplete label="Fruit" options={['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']} />
494
+ <Autocomplete
495
+ label="Fruit"
496
+ options={['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry']}
497
+ />
754
498
  ```
755
499
 
756
500
  ### Controlled vs Uncontrolled
@@ -760,12 +504,23 @@ const options = [
760
504
  function ControlledExample() {
761
505
  const [value, setValue] = useState<string | undefined>();
762
506
 
763
- return <Autocomplete value={value} onChange={(e) => setValue(e.target.value)} options={options} />;
507
+ return (
508
+ <Autocomplete
509
+ value={value}
510
+ onChange={(e) => setValue(e.target.value)}
511
+ options={options}
512
+ />
513
+ );
764
514
  }
765
515
 
766
516
  // Uncontrolled - internal state management
767
517
  function UncontrolledExample() {
768
- return <Autocomplete defaultValue="option-1" options={options} />;
518
+ return (
519
+ <Autocomplete
520
+ defaultValue="option-1"
521
+ options={options}
522
+ />
523
+ );
769
524
  }
770
525
  ```
771
526
 
@@ -799,7 +554,12 @@ function UncontrolledExample() {
799
554
  ### Multiple Selection
800
555
 
801
556
  ```tsx
802
- <Autocomplete multiple value={['option-1', 'option-2']} options={options} onChange={(e) => setValues(e.target.value)} />
557
+ <Autocomplete
558
+ multiple
559
+ value={['option-1', 'option-2']}
560
+ options={options}
561
+ onChange={(e) => setValues(e.target.value)}
562
+ />
803
563
  ```
804
564
 
805
565
  ## Accessibility
@@ -818,7 +578,7 @@ Autocomplete includes comprehensive accessibility features:
818
578
  - **Arrow Down**: Open dropdown / move to next option
819
579
  - **Arrow Up**: Move to previous option
820
580
  - **Enter**: Select focused option
821
- - **Escape**: Close dropdown (clears value if `clearOnEscape` is enabled)
581
+ - **Escape**: Close dropdown
822
582
  - **Tab**: Move focus out of component
823
583
  - **Home**: Jump to first option
824
584
  - **End**: Jump to last option
@@ -829,7 +589,7 @@ Autocomplete includes comprehensive accessibility features:
829
589
  ```tsx
830
590
  // Proper labeling for screen readers
831
591
  <Autocomplete
832
- label="Select a country" // Announces: "Select a country, combobox"
592
+ label="Select a country" // Announces: "Select a country, combobox"
833
593
  placeholder="Search..."
834
594
  options={countries}
835
595
  />
@@ -843,11 +603,6 @@ Autocomplete includes comprehensive accessibility features:
843
603
  - Focus returns to input when selecting an option
844
604
  - Clear visual focus indicators on all interactive elements
845
605
 
846
- ### Read Only vs Disabled Semantics
847
-
848
- - **`readOnly`**: The input is focusable, its value can be copied, and screen readers announce it as read-only. Use when a value should be visible but not editable.
849
- - **`disabled`**: The input is not focusable and is skipped in tab order. Use when the field is temporarily unavailable.
850
-
851
606
  ## Best Practices
852
607
 
853
608
  ### ✅ Do
@@ -856,21 +611,32 @@ Autocomplete includes comprehensive accessibility features:
856
611
 
857
612
  ```tsx
858
613
  // ✅ Good: Clear label and placeholder
859
- <Autocomplete label="Shipping Country" placeholder="Type to search countries..." options={countries} />
614
+ <Autocomplete
615
+ label="Shipping Country"
616
+ placeholder="Type to search countries..."
617
+ options={countries}
618
+ />
860
619
  ```
861
620
 
862
621
  2. **Show loading state during async operations**: Keep users informed
863
622
 
864
623
  ```tsx
865
624
  // ✅ Good: Loading indicator while fetching
866
- <Autocomplete options={options} loading={isLoading} placeholder={isLoading ? 'Loading...' : 'Search...'} />
625
+ <Autocomplete
626
+ options={options}
627
+ loading={isLoading}
628
+ placeholder={isLoading ? 'Loading...' : 'Search...'}
629
+ />
867
630
  ```
868
631
 
869
632
  3. **Use grouping for better organization**: Help users scan large lists
870
633
 
871
634
  ```tsx
872
635
  // ✅ Good: Logical grouping
873
- <Autocomplete options={allProducts} groupBy={(product) => product.category} />
636
+ <Autocomplete
637
+ options={allProducts}
638
+ groupBy={(product) => product.category}
639
+ />
874
640
  ```
875
641
 
876
642
  4. **Debounce API searches**: Prevent excessive requests
@@ -883,20 +649,6 @@ useEffect(() => {
883
649
  }, [query]);
884
650
  ```
885
651
 
886
- 5. **Use `disableCloseOnSelect` with `multiple`**: Keep the popup open for batch selection
887
-
888
- ```tsx
889
- // ✅ Good: Popup stays open for multiple selections
890
- <Autocomplete multiple disableCloseOnSelect options={tags} />
891
- ```
892
-
893
- 6. **Set `limitTags` for constrained layouts**: Prevent tag overflow
894
-
895
- ```tsx
896
- // ✅ Good: Show at most 3 tags, truncate the rest
897
- <Autocomplete multiple limitTags={3} options={allTags} />
898
- ```
899
-
900
652
  ### ❌ Don't
901
653
 
902
654
  1. **Don't use for small option sets**: Use Select instead
@@ -934,36 +686,20 @@ useEffect(() => {
934
686
 
935
687
  ```tsx
936
688
  // ✅ Good: Handle empty results
937
- <Autocomplete options={filteredOptions} noOptionsText="No matches found. Try a different search." />
689
+ <Autocomplete
690
+ options={filteredOptions}
691
+ noOptionsText="No matches found. Try a different search."
692
+ />
938
693
  ```
939
694
 
940
695
  4. **Don't block interaction during initial load**: Show placeholders
941
696
 
942
697
  ```tsx
943
698
  // ❌ Bad: Blocking the entire form
944
- {
945
- loading ? <Spinner /> : <Autocomplete options={options} />;
946
- }
699
+ {loading ? <Spinner /> : <Autocomplete options={options} />}
947
700
 
948
701
  // ✅ Good: Allow interaction with loading state
949
- <Autocomplete options={options} loading={loading} />;
950
- ```
951
-
952
- 5. **Don't rely on `freeSolo` for validated input without extra handling**: Validate free-text values
953
-
954
- ```tsx
955
- // ❌ Bad: No validation for free-text input
956
- <Autocomplete freeSolo options={emails} />
957
-
958
- // ✅ Good: Validate free-text input via onInputChange
959
- <Autocomplete
960
- freeSolo
961
- options={emails}
962
- onInputChange={(e) => {
963
- const value = e.target.value;
964
- setError(!isValidEmail(value));
965
- }}
966
- />
702
+ <Autocomplete options={options} loading={loading} />
967
703
  ```
968
704
 
969
705
  ## Performance Considerations
@@ -974,7 +710,9 @@ Autocomplete automatically virtualizes long lists for performance:
974
710
 
975
711
  ```tsx
976
712
  // Handles 1000+ options efficiently
977
- <Autocomplete options={Array.from({ length: 1000 }, (_, i) => `Option ${i + 1}`)} />
713
+ <Autocomplete
714
+ options={Array.from({ length: 1000 }, (_, i) => `Option ${i + 1}`)}
715
+ />
978
716
  ```
979
717
 
980
718
  ### Debounce Search Requests
@@ -1001,10 +739,16 @@ function SearchAutocomplete({ fetchOptions }) {
1001
739
  setLoading(false);
1002
740
  }
1003
741
  }, 300),
1004
- [fetchOptions],
742
+ [fetchOptions]
1005
743
  );
1006
744
 
1007
- return <Autocomplete options={options} loading={loading} onInputChange={(e) => debouncedFetch(e.target.value)} />;
745
+ return (
746
+ <Autocomplete
747
+ options={options}
748
+ loading={loading}
749
+ onInputChange={(e) => debouncedFetch(e.target.value)}
750
+ />
751
+ );
1008
752
  }
1009
753
  ```
1010
754
 
@@ -1020,10 +764,10 @@ const options = useMemo(
1020
764
  label: item.name,
1021
765
  startDecorator: <StatusChip status={item.status} />,
1022
766
  })),
1023
- [data],
767
+ [data]
1024
768
  );
1025
769
 
1026
- <Autocomplete options={options} />;
770
+ <Autocomplete options={options} />
1027
771
  ```
1028
772
 
1029
773
  ### Lazy Load Options
@@ -1049,7 +793,14 @@ function LazyLoadAutocomplete() {
1049
793
  }
1050
794
  };
1051
795
 
1052
- return <Autocomplete options={options} loading={loading} onFocus={loadOptions} onOpen={loadOptions} />;
796
+ return (
797
+ <Autocomplete
798
+ options={options}
799
+ loading={loading}
800
+ onFocus={loadOptions}
801
+ onOpen={loadOptions}
802
+ />
803
+ );
1053
804
  }
1054
805
  ```
1055
806
 
@@ -1077,7 +828,7 @@ const options = useMemo(
1077
828
  label: user.name,
1078
829
  startDecorator: <MemoizedOption option={user} />,
1079
830
  })),
1080
- [users],
831
+ [users]
1081
832
  );
1082
833
  ```
1083
834