@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.
- 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/hooks.d.ts +2 -1
- package/dist/components/DataTable/utils.d.ts +1 -0
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
- package/dist/components/SearchBar/SearchBar.d.ts +21 -0
- package/dist/components/SearchBar/index.d.ts +3 -0
- package/dist/components/data-display/Badge.md +39 -71
- package/dist/components/data-display/DataTable.md +1 -1
- package/dist/components/data-display/InfoSign.md +98 -74
- package/dist/components/data-display/Typography.md +97 -363
- package/dist/components/feedback/Dialog.md +62 -76
- package/dist/components/feedback/Modal.md +44 -259
- package/dist/components/feedback/llms.txt +0 -2
- package/dist/components/index.d.ts +2 -0
- package/dist/components/inputs/Autocomplete.md +107 -356
- package/dist/components/inputs/ButtonGroup.md +106 -115
- package/dist/components/inputs/Calendar.md +459 -98
- package/dist/components/inputs/CurrencyInput.md +5 -183
- package/dist/components/inputs/DatePicker.md +431 -108
- package/dist/components/inputs/DateRangePicker.md +492 -131
- package/dist/components/inputs/FilterMenu.md +19 -169
- package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
- package/dist/components/inputs/IconButton.md +88 -137
- package/dist/components/inputs/Input.md +0 -5
- package/dist/components/inputs/MonthPicker.md +422 -95
- package/dist/components/inputs/MonthRangePicker.md +466 -89
- package/dist/components/inputs/PercentageInput.md +16 -185
- package/dist/components/inputs/RadioButton.md +35 -163
- package/dist/components/inputs/RadioTileGroup.md +61 -150
- package/dist/components/inputs/SearchBar.md +44 -0
- package/dist/components/inputs/Select.md +326 -222
- package/dist/components/inputs/Switch.md +376 -136
- package/dist/components/inputs/Textarea.md +10 -213
- package/dist/components/inputs/Uploader/Uploader.md +66 -145
- package/dist/components/inputs/llms.txt +1 -3
- package/dist/components/navigation/Breadcrumbs.md +322 -80
- package/dist/components/navigation/Dropdown.md +221 -92
- package/dist/components/navigation/IconMenuButton.md +502 -40
- package/dist/components/navigation/InsetDrawer.md +738 -68
- package/dist/components/navigation/Link.md +298 -39
- package/dist/components/navigation/Menu.md +285 -92
- package/dist/components/navigation/MenuButton.md +448 -55
- package/dist/components/navigation/Pagination.md +338 -47
- package/dist/components/navigation/ProfileMenu.md +268 -45
- package/dist/components/navigation/Stepper.md +28 -160
- package/dist/components/navigation/Tabs.md +316 -57
- package/dist/components/surfaces/Sheet.md +334 -151
- package/dist/index.browser.js +15 -13
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +313 -291
- package/dist/index.d.ts +1 -1
- package/dist/index.js +450 -372
- package/dist/llms.txt +1 -8
- package/framer/index.js +1 -1
- package/package.json +16 -15
- package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
- package/dist/components/feedback/CircularProgress.md +0 -257
- package/dist/components/feedback/Skeleton.md +0 -280
- package/dist/components/inputs/FormControl.md +0 -361
- package/dist/components/inputs/RadioList.md +0 -241
- package/dist/components/inputs/Slider.md +0 -334
- package/dist/guides/ThemeProvider.md +0 -116
- package/dist/guides/llms.txt +0 -9
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
-
The Select component is a form input that allows users to choose one or multiple options from a predefined list. Built on Joy UI's Select, it provides a dropdown interface for
|
|
6
|
-
|
|
7
|
-
Select accepts options as an array of objects (with `value`, `label`, and optional `secondaryText` / `disabled` fields) or as simple string/number arrays. It wraps the underlying select element with built-in `FormControl`, `FormLabel`, and `FormHelperText` so you can compose complete form fields with a single component.
|
|
5
|
+
The Select component is a form input that allows users to choose one or multiple options from a predefined list. Built on Joy UI's Select, it provides a dropdown interface for selecting values within forms. Select is designed for data input scenarios where users need to pick from a set of options, making it ideal for forms, filters, and configuration settings.
|
|
8
6
|
|
|
9
7
|
```tsx
|
|
10
8
|
<Select options={options} />
|
|
@@ -26,21 +24,16 @@ Select accepts options as an array of objects (with `value`, `label`, and option
|
|
|
26
24
|
| onChange | — | — |
|
|
27
25
|
| options | — | options |
|
|
28
26
|
|
|
29
|
-
> **Don't
|
|
30
|
-
>
|
|
31
|
-
> - **Select**: For form value selection -- the selected value becomes form data.
|
|
32
|
-
> - **Dropdown**: For menus and action lists -- triggers actions or navigation.
|
|
27
|
+
> ⚠️ **Don't Confuse Select with Dropdown** ⚠️
|
|
33
28
|
>
|
|
34
|
-
>
|
|
29
|
+
> - **Select**: For form value selection - the selected value becomes form data
|
|
30
|
+
> - **Dropdown**: For menus and action lists - triggers actions or navigation
|
|
35
31
|
>
|
|
36
|
-
>
|
|
37
|
-
> - More than 20 options -- consider Autocomplete with search
|
|
38
|
-
> - Actions / navigation -- use Dropdown with Menu
|
|
39
|
-
|
|
40
|
-
> **Use built-in form props**
|
|
32
|
+
> Choose the right component:
|
|
41
33
|
>
|
|
42
|
-
>
|
|
43
|
-
>
|
|
34
|
+
> - Less than 5 options → Consider RadioButton or RadioGroup
|
|
35
|
+
> - More than 20 options → Consider Autocomplete with search
|
|
36
|
+
> - Actions/navigation → Use Dropdown with Menu
|
|
44
37
|
|
|
45
38
|
## Usage
|
|
46
39
|
|
|
@@ -64,9 +57,19 @@ function MyComponent() {
|
|
|
64
57
|
}
|
|
65
58
|
```
|
|
66
59
|
|
|
67
|
-
##
|
|
60
|
+
## Examples
|
|
61
|
+
|
|
62
|
+
### Basic Select
|
|
63
|
+
|
|
64
|
+
The default Select with a list of options.
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<Select options={options} />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Variants
|
|
68
71
|
|
|
69
|
-
Select supports
|
|
72
|
+
Select supports different visual styles.
|
|
70
73
|
|
|
71
74
|
```tsx
|
|
72
75
|
<Stack spacing={4}>
|
|
@@ -77,16 +80,9 @@ Select supports four visual styles: `outlined` (default), `plain`, `soft`, and `
|
|
|
77
80
|
</Stack>
|
|
78
81
|
```
|
|
79
82
|
|
|
80
|
-
|
|
81
|
-
<Select options={options} defaultValue="dog" />
|
|
82
|
-
<Select options={options} defaultValue="dog" variant="plain" />
|
|
83
|
-
<Select options={options} defaultValue="dog" variant="soft" />
|
|
84
|
-
<Select options={options} defaultValue="dog" variant="solid" />
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
## Sizes
|
|
83
|
+
### Sizes
|
|
88
84
|
|
|
89
|
-
|
|
85
|
+
Select comes in different sizes.
|
|
90
86
|
|
|
91
87
|
```tsx
|
|
92
88
|
<Stack spacing={4}>
|
|
@@ -96,15 +92,9 @@ Three sizes are available: `sm`, `md` (default), and `lg`.
|
|
|
96
92
|
</Stack>
|
|
97
93
|
```
|
|
98
94
|
|
|
99
|
-
|
|
100
|
-
<Select options={options} defaultValue="dog" size="sm" />
|
|
101
|
-
<Select options={options} defaultValue="dog" size="md" />
|
|
102
|
-
<Select options={options} defaultValue="dog" size="lg" />
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
## Colors
|
|
95
|
+
### Colors
|
|
106
96
|
|
|
107
|
-
Apply semantic colors to
|
|
97
|
+
Apply semantic colors to Select.
|
|
108
98
|
|
|
109
99
|
```tsx
|
|
110
100
|
<Stack spacing={4}>
|
|
@@ -116,17 +106,9 @@ Apply semantic colors to communicate intent or state.
|
|
|
116
106
|
</Stack>
|
|
117
107
|
```
|
|
118
108
|
|
|
119
|
-
|
|
120
|
-
<Select options={options} defaultValue="dog" color="primary" />
|
|
121
|
-
<Select options={options} defaultValue="dog" color="neutral" />
|
|
122
|
-
<Select options={options} defaultValue="dog" color="success" />
|
|
123
|
-
<Select options={options} defaultValue="dog" color="danger" />
|
|
124
|
-
<Select options={options} defaultValue="dog" color="warning" />
|
|
125
|
-
```
|
|
109
|
+
### With Decorators
|
|
126
110
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
Use `startDecorator` and `endDecorator` to add icons, badges, or other elements beside the select trigger.
|
|
111
|
+
Add icons or badges to the Select.
|
|
130
112
|
|
|
131
113
|
```tsx
|
|
132
114
|
<Select placeholder="Select a pet…" startDecorator={<FavoriteBorder />} endDecorator={<Chip size="sm" color="danger" variant="soft">
|
|
@@ -136,24 +118,9 @@ width: 240
|
|
|
136
118
|
}} options={options} />
|
|
137
119
|
```
|
|
138
120
|
|
|
139
|
-
|
|
140
|
-
import FavoriteBorder from '@mui/icons-material/FavoriteBorder';
|
|
141
|
-
import { Chip } from '@ceed/ads';
|
|
121
|
+
### With Label
|
|
142
122
|
|
|
143
|
-
|
|
144
|
-
placeholder="Select a pet..."
|
|
145
|
-
startDecorator={<FavoriteBorder />}
|
|
146
|
-
endDecorator={
|
|
147
|
-
<Chip size="sm" color="danger" variant="soft">+5</Chip>
|
|
148
|
-
}
|
|
149
|
-
options={options}
|
|
150
|
-
sx={{ width: 240 }}
|
|
151
|
-
/>
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Label and Helper Text
|
|
155
|
-
|
|
156
|
-
The `label` prop renders a form label above the select. The `helperText` prop renders descriptive text below it. Both are built into the component so you do not need to compose them separately.
|
|
123
|
+
Select with an associated label.
|
|
157
124
|
|
|
158
125
|
```tsx
|
|
159
126
|
<>
|
|
@@ -161,26 +128,19 @@ The `label` prop renders a form label above the select. The `helperText` prop re
|
|
|
161
128
|
</>
|
|
162
129
|
```
|
|
163
130
|
|
|
131
|
+
### With Helper Text
|
|
132
|
+
|
|
133
|
+
Add helper text for additional context.
|
|
134
|
+
|
|
164
135
|
```tsx
|
|
165
136
|
<>
|
|
166
137
|
<Select label="Select" helperText="I'm helper text" defaultValue="dog" options={options} />
|
|
167
138
|
</>
|
|
168
139
|
```
|
|
169
140
|
|
|
170
|
-
|
|
171
|
-
<Select label="Pet" options={options} defaultValue="dog" />
|
|
141
|
+
### Error State
|
|
172
142
|
|
|
173
|
-
|
|
174
|
-
label="Pet"
|
|
175
|
-
helperText="Choose your favorite animal"
|
|
176
|
-
options={options}
|
|
177
|
-
defaultValue="dog"
|
|
178
|
-
/>
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
## Error State
|
|
182
|
-
|
|
183
|
-
Set `error` to `true` to visually indicate a validation error. Combine with `helperText` to display an error message.
|
|
143
|
+
Show validation errors.
|
|
184
144
|
|
|
185
145
|
```tsx
|
|
186
146
|
<>
|
|
@@ -188,18 +148,9 @@ Set `error` to `true` to visually indicate a validation error. Combine with `hel
|
|
|
188
148
|
</>
|
|
189
149
|
```
|
|
190
150
|
|
|
191
|
-
|
|
192
|
-
<Select
|
|
193
|
-
label="Pet"
|
|
194
|
-
error
|
|
195
|
-
helperText="This field is required"
|
|
196
|
-
options={options}
|
|
197
|
-
/>
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Form Control
|
|
151
|
+
### Form Control
|
|
201
152
|
|
|
202
|
-
|
|
153
|
+
Complete form integration with label and helper text.
|
|
203
154
|
|
|
204
155
|
```tsx
|
|
205
156
|
<>
|
|
@@ -208,9 +159,9 @@ Combining `label`, `helperText`, and `error` produces a complete form field. Her
|
|
|
208
159
|
</>
|
|
209
160
|
```
|
|
210
161
|
|
|
211
|
-
|
|
162
|
+
### Required Field
|
|
212
163
|
|
|
213
|
-
|
|
164
|
+
Mark the Select as required.
|
|
214
165
|
|
|
215
166
|
```tsx
|
|
216
167
|
<Select
|
|
@@ -221,18 +172,9 @@ Set `required` to mark the field as required. An asterisk is added to the label
|
|
|
221
172
|
/>
|
|
222
173
|
```
|
|
223
174
|
|
|
224
|
-
|
|
225
|
-
<Select
|
|
226
|
-
label="Pet"
|
|
227
|
-
helperText="This field is required"
|
|
228
|
-
required
|
|
229
|
-
options={options}
|
|
230
|
-
/>
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
## Multiple Selection
|
|
175
|
+
### Multiple Selection
|
|
234
176
|
|
|
235
|
-
|
|
177
|
+
Allow selecting multiple options.
|
|
236
178
|
|
|
237
179
|
```tsx
|
|
238
180
|
<Select
|
|
@@ -244,18 +186,9 @@ Set `multiple` to allow selecting more than one option. The value becomes an arr
|
|
|
244
186
|
/>
|
|
245
187
|
```
|
|
246
188
|
|
|
247
|
-
|
|
248
|
-
<Select
|
|
249
|
-
label="Pets"
|
|
250
|
-
multiple
|
|
251
|
-
defaultValue={['dog']}
|
|
252
|
-
options={options}
|
|
253
|
-
/>
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
## Controlled Select
|
|
189
|
+
### Controlled Select
|
|
257
190
|
|
|
258
|
-
|
|
191
|
+
Programmatically control the selected value.
|
|
259
192
|
|
|
260
193
|
```tsx
|
|
261
194
|
<div>
|
|
@@ -274,20 +207,9 @@ Use the `value` and `onChange` props for controlled behavior when you need to sy
|
|
|
274
207
|
</div>
|
|
275
208
|
```
|
|
276
209
|
|
|
277
|
-
|
|
278
|
-
const [value, setValue] = useState('dog');
|
|
279
|
-
|
|
280
|
-
<Select
|
|
281
|
-
label="Pet"
|
|
282
|
-
value={value}
|
|
283
|
-
onChange={(event, newValue) => setValue(newValue)}
|
|
284
|
-
options={options}
|
|
285
|
-
/>
|
|
286
|
-
```
|
|
287
|
-
|
|
288
|
-
## Disabled Options
|
|
210
|
+
### Disabled Options
|
|
289
211
|
|
|
290
|
-
Individual options can be disabled
|
|
212
|
+
Individual options can be disabled.
|
|
291
213
|
|
|
292
214
|
```tsx
|
|
293
215
|
<Select
|
|
@@ -300,20 +222,9 @@ Individual options can be disabled by setting `disabled: true` on the option obj
|
|
|
300
222
|
/>
|
|
301
223
|
```
|
|
302
224
|
|
|
303
|
-
|
|
304
|
-
const options = [
|
|
305
|
-
{ value: 'dog', label: 'Dog', disabled: true },
|
|
306
|
-
{ value: 'cat', label: 'Cat' },
|
|
307
|
-
{ value: 'fish', label: 'Fish', disabled: true },
|
|
308
|
-
{ value: 'bird', label: 'Bird' },
|
|
309
|
-
];
|
|
310
|
-
|
|
311
|
-
<Select label="Pet" options={options} defaultValue="dog" />
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
## Options with Secondary Text
|
|
225
|
+
### Options with Secondary Text
|
|
315
226
|
|
|
316
|
-
|
|
227
|
+
Display additional information for each option.
|
|
317
228
|
|
|
318
229
|
```tsx
|
|
319
230
|
<Stack spacing={4} direction="row" alignItems="flex-start">
|
|
@@ -329,76 +240,58 @@ Add a `secondaryText` field to display supplementary information below each opti
|
|
|
329
240
|
</Stack>
|
|
330
241
|
```
|
|
331
242
|
|
|
332
|
-
|
|
333
|
-
const userOptions = [
|
|
334
|
-
{ value: 'emily', label: 'Emily Carter', secondaryText: '(415) 555-0198' },
|
|
335
|
-
{ value: 'daniel', label: 'Daniel Kim', secondaryText: '(212) 555-0421' },
|
|
336
|
-
{ value: 'sophia', label: 'Sophia Martinez', secondaryText: '(646) 555-0734' },
|
|
337
|
-
];
|
|
243
|
+
## When to Use
|
|
338
244
|
|
|
339
|
-
|
|
340
|
-
```
|
|
245
|
+
### ✅ Good Use Cases
|
|
341
246
|
|
|
342
|
-
|
|
247
|
+
- **Forms**: When users need to select a value that will be submitted as form data
|
|
248
|
+
- **Filters**: Selecting filter criteria for lists or search results
|
|
249
|
+
- **Settings**: Configuration options where user needs to pick one value
|
|
250
|
+
- **Data entry**: Standardized input where free text isn't appropriate
|
|
251
|
+
- **5-20 options**: Ideal number of choices for a Select
|
|
252
|
+
- **Single source of truth**: When the selected value should be clearly visible
|
|
343
253
|
|
|
344
|
-
|
|
254
|
+
### ❌ When Not to Use
|
|
345
255
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
<Select defaultValue={1} variant="solid" options={numericOptions} />
|
|
352
|
-
</Stack>
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
```tsx
|
|
356
|
-
const numericOptions = [
|
|
357
|
-
{ value: 1, label: 'Option 1' },
|
|
358
|
-
{ value: 2, label: 'Option 2' },
|
|
359
|
-
{ value: 3, label: 'Option 3' },
|
|
360
|
-
];
|
|
361
|
-
|
|
362
|
-
<Select options={numericOptions} defaultValue={1} />
|
|
363
|
-
```
|
|
256
|
+
- **Actions/navigation**: Use Dropdown with Menu instead
|
|
257
|
+
- **2-4 options visible at once**: Consider RadioGroup for better visibility
|
|
258
|
+
- **20+ options**: Use Autocomplete with search functionality
|
|
259
|
+
- **Complex selections**: Consider a different pattern if selections involve complex logic
|
|
260
|
+
- **Toggle between states**: Use Switch or Checkbox instead
|
|
364
261
|
|
|
365
262
|
## Common Use Cases
|
|
366
263
|
|
|
367
|
-
### Form with
|
|
264
|
+
### Form with Select
|
|
368
265
|
|
|
369
266
|
```tsx
|
|
370
|
-
import { useState } from 'react';
|
|
371
|
-
import { Select, Button, Stack } from '@ceed/ads';
|
|
372
|
-
|
|
373
267
|
function UserForm() {
|
|
374
|
-
const [
|
|
375
|
-
const [
|
|
376
|
-
|
|
377
|
-
const handleSubmit = (e: React.FormEvent) => {
|
|
378
|
-
e.preventDefault();
|
|
379
|
-
setSubmitted(true);
|
|
380
|
-
if (role) {
|
|
381
|
-
// submit form
|
|
382
|
-
}
|
|
383
|
-
};
|
|
268
|
+
const [country, setCountry] = useState('');
|
|
269
|
+
const [role, setRole] = useState('');
|
|
384
270
|
|
|
385
271
|
return (
|
|
386
272
|
<form onSubmit={handleSubmit}>
|
|
387
273
|
<Stack spacing={2}>
|
|
274
|
+
<Select
|
|
275
|
+
label="Country"
|
|
276
|
+
required
|
|
277
|
+
value={country}
|
|
278
|
+
onChange={(e, val) => setCountry(val)}
|
|
279
|
+
options={countries}
|
|
280
|
+
placeholder="Select your country"
|
|
281
|
+
/>
|
|
282
|
+
|
|
388
283
|
<Select
|
|
389
284
|
label="Role"
|
|
390
285
|
required
|
|
391
286
|
value={role}
|
|
392
287
|
onChange={(e, val) => setRole(val)}
|
|
393
|
-
error={submitted && !role}
|
|
394
|
-
helperText={submitted && !role ? 'Please select a role' : undefined}
|
|
395
288
|
options={[
|
|
396
289
|
{ value: 'admin', label: 'Administrator' },
|
|
397
290
|
{ value: 'editor', label: 'Editor' },
|
|
398
291
|
{ value: 'viewer', label: 'Viewer' },
|
|
399
292
|
]}
|
|
400
|
-
placeholder="Select a role..."
|
|
401
293
|
/>
|
|
294
|
+
|
|
402
295
|
<Button type="submit">Submit</Button>
|
|
403
296
|
</Stack>
|
|
404
297
|
</form>
|
|
@@ -406,11 +299,9 @@ function UserForm() {
|
|
|
406
299
|
}
|
|
407
300
|
```
|
|
408
301
|
|
|
409
|
-
### Filter
|
|
302
|
+
### Filter Select
|
|
410
303
|
|
|
411
304
|
```tsx
|
|
412
|
-
import { Select, Stack } from '@ceed/ads';
|
|
413
|
-
|
|
414
305
|
function ProductFilter({ onFilterChange }) {
|
|
415
306
|
const [category, setCategory] = useState('all');
|
|
416
307
|
const [sortBy, setSortBy] = useState('newest');
|
|
@@ -430,8 +321,10 @@ function ProductFilter({ onFilterChange }) {
|
|
|
430
321
|
{ value: 'all', label: 'All Categories' },
|
|
431
322
|
{ value: 'electronics', label: 'Electronics' },
|
|
432
323
|
{ value: 'clothing', label: 'Clothing' },
|
|
324
|
+
{ value: 'home', label: 'Home & Garden' },
|
|
433
325
|
]}
|
|
434
326
|
/>
|
|
327
|
+
|
|
435
328
|
<Select
|
|
436
329
|
label="Sort By"
|
|
437
330
|
size="sm"
|
|
@@ -441,6 +334,7 @@ function ProductFilter({ onFilterChange }) {
|
|
|
441
334
|
{ value: 'newest', label: 'Newest First' },
|
|
442
335
|
{ value: 'price-low', label: 'Price: Low to High' },
|
|
443
336
|
{ value: 'price-high', label: 'Price: High to Low' },
|
|
337
|
+
{ value: 'popular', label: 'Most Popular' },
|
|
444
338
|
]}
|
|
445
339
|
/>
|
|
446
340
|
</Stack>
|
|
@@ -448,15 +342,39 @@ function ProductFilter({ onFilterChange }) {
|
|
|
448
342
|
}
|
|
449
343
|
```
|
|
450
344
|
|
|
451
|
-
###
|
|
345
|
+
### Multiple Select with Tags
|
|
452
346
|
|
|
453
347
|
```tsx
|
|
454
|
-
|
|
455
|
-
|
|
348
|
+
function TagSelect() {
|
|
349
|
+
const [selectedTags, setSelectedTags] = useState([]);
|
|
350
|
+
|
|
351
|
+
const tagOptions = [
|
|
352
|
+
{ value: 'urgent', label: 'Urgent' },
|
|
353
|
+
{ value: 'feature', label: 'Feature' },
|
|
354
|
+
{ value: 'bug', label: 'Bug' },
|
|
355
|
+
{ value: 'enhancement', label: 'Enhancement' },
|
|
356
|
+
{ value: 'documentation', label: 'Documentation' },
|
|
357
|
+
];
|
|
358
|
+
|
|
359
|
+
return (
|
|
360
|
+
<Select
|
|
361
|
+
label="Tags"
|
|
362
|
+
multiple
|
|
363
|
+
value={selectedTags}
|
|
364
|
+
onChange={(e, val) => setSelectedTags(val)}
|
|
365
|
+
options={tagOptions}
|
|
366
|
+
placeholder="Select tags..."
|
|
367
|
+
/>
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
```
|
|
456
371
|
|
|
372
|
+
### Dependent Selects
|
|
373
|
+
|
|
374
|
+
```tsx
|
|
457
375
|
function LocationSelect() {
|
|
458
|
-
const [country, setCountry] = useState
|
|
459
|
-
const [city, setCity] = useState
|
|
376
|
+
const [country, setCountry] = useState('');
|
|
377
|
+
const [city, setCity] = useState('');
|
|
460
378
|
|
|
461
379
|
const cities = useMemo(() => {
|
|
462
380
|
if (!country) return [];
|
|
@@ -470,83 +388,269 @@ function LocationSelect() {
|
|
|
470
388
|
value={country}
|
|
471
389
|
onChange={(e, val) => {
|
|
472
390
|
setCountry(val);
|
|
473
|
-
setCity(
|
|
391
|
+
setCity(''); // Reset city when country changes
|
|
474
392
|
}}
|
|
475
393
|
options={countries}
|
|
476
|
-
placeholder="Select a country"
|
|
477
394
|
/>
|
|
395
|
+
|
|
478
396
|
<Select
|
|
479
397
|
label="City"
|
|
480
398
|
value={city}
|
|
481
399
|
onChange={(e, val) => setCity(val)}
|
|
482
400
|
options={cities}
|
|
483
401
|
disabled={!country}
|
|
484
|
-
placeholder={country ? 'Select
|
|
402
|
+
placeholder={country ? 'Select city' : 'Select country first'}
|
|
485
403
|
/>
|
|
486
404
|
</Stack>
|
|
487
405
|
);
|
|
488
406
|
}
|
|
489
407
|
```
|
|
490
408
|
|
|
409
|
+
### With Custom Option Rendering
|
|
410
|
+
|
|
411
|
+
```tsx
|
|
412
|
+
function UserSelect() {
|
|
413
|
+
const userOptions = [
|
|
414
|
+
{ value: 'user1', label: 'John Doe', secondaryText: 'john@example.com' },
|
|
415
|
+
{ value: 'user2', label: 'Jane Smith', secondaryText: 'jane@example.com' },
|
|
416
|
+
{ value: 'user3', label: 'Bob Johnson', secondaryText: 'bob@example.com' },
|
|
417
|
+
];
|
|
418
|
+
|
|
419
|
+
return (
|
|
420
|
+
<Select
|
|
421
|
+
label="Assign to"
|
|
422
|
+
options={userOptions}
|
|
423
|
+
placeholder="Select a user..."
|
|
424
|
+
/>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Props and Customization
|
|
430
|
+
|
|
431
|
+
### Key Props
|
|
432
|
+
|
|
433
|
+
| Prop | Type | Default | Description |
|
|
434
|
+
| -------------- | -------------------------------------------------------------- | ------------ | ------------------------------- |
|
|
435
|
+
| `options` | `Option[]` | `[]` | Array of options to display |
|
|
436
|
+
| `value` | `T \| T[]` | - | Selected value(s) (controlled) |
|
|
437
|
+
| `defaultValue` | `T \| T[]` | - | Default value (uncontrolled) |
|
|
438
|
+
| `onChange` | `function` | - | Callback when selection changes |
|
|
439
|
+
| `multiple` | `boolean` | `false` | Allow multiple selections |
|
|
440
|
+
| `label` | `string` | - | Label text above the Select |
|
|
441
|
+
| `helperText` | `string` | - | Helper text below the Select |
|
|
442
|
+
| `error` | `boolean` | `false` | Show error state |
|
|
443
|
+
| `required` | `boolean` | `false` | Mark as required |
|
|
444
|
+
| `disabled` | `boolean` | `false` | Disable the Select |
|
|
445
|
+
| `placeholder` | `string` | - | Placeholder text |
|
|
446
|
+
| `variant` | `'plain' \| 'outlined' \| 'soft' \| 'solid'` | `'outlined'` | Visual style |
|
|
447
|
+
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | - | Color scheme |
|
|
448
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Component size |
|
|
449
|
+
|
|
450
|
+
### Option Type
|
|
451
|
+
|
|
452
|
+
```tsx
|
|
453
|
+
interface Option {
|
|
454
|
+
value: string | number;
|
|
455
|
+
label: string;
|
|
456
|
+
secondaryText?: string;
|
|
457
|
+
disabled?: boolean;
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### Numeric Values
|
|
462
|
+
|
|
463
|
+
Select supports both string and numeric values:
|
|
464
|
+
|
|
465
|
+
```tsx
|
|
466
|
+
<Stack spacing={4}>
|
|
467
|
+
<Select defaultValue={1} options={numericOptions} />
|
|
468
|
+
<Select defaultValue={1} variant="plain" options={numericOptions} />
|
|
469
|
+
<Select defaultValue={1} variant="soft" options={numericOptions} />
|
|
470
|
+
<Select defaultValue={1} variant="solid" options={numericOptions} />
|
|
471
|
+
</Stack>
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
```tsx
|
|
475
|
+
const numericOptions = [
|
|
476
|
+
{ value: 1, label: 'Option 1' },
|
|
477
|
+
{ value: 2, label: 'Option 2' },
|
|
478
|
+
{ value: 3, label: 'Option 3' },
|
|
479
|
+
];
|
|
480
|
+
|
|
481
|
+
<Select options={numericOptions} defaultValue={1} />
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Custom Styling
|
|
485
|
+
|
|
486
|
+
```tsx
|
|
487
|
+
<Select
|
|
488
|
+
options={options}
|
|
489
|
+
sx={{
|
|
490
|
+
minWidth: 200,
|
|
491
|
+
'& .MuiSelect-button': {
|
|
492
|
+
borderRadius: 'xl',
|
|
493
|
+
},
|
|
494
|
+
}}
|
|
495
|
+
/>
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
## Accessibility
|
|
499
|
+
|
|
500
|
+
Select components follow accessibility best practices:
|
|
501
|
+
|
|
502
|
+
### ARIA Attributes
|
|
503
|
+
|
|
504
|
+
- Uses native listbox role with proper ARIA attributes
|
|
505
|
+
- `aria-labelledby` connects to the label
|
|
506
|
+
- `aria-describedby` connects to helper text
|
|
507
|
+
- `aria-required` when required prop is true
|
|
508
|
+
- `aria-invalid` when error prop is true
|
|
509
|
+
|
|
510
|
+
### Keyboard Navigation
|
|
511
|
+
|
|
512
|
+
- **Tab**: Focus the Select
|
|
513
|
+
- **Enter/Space**: Open the dropdown
|
|
514
|
+
- **Arrow Up/Down**: Navigate through options
|
|
515
|
+
- **Home/End**: Jump to first/last option
|
|
516
|
+
- **Enter**: Select the focused option
|
|
517
|
+
- **Escape**: Close the dropdown
|
|
518
|
+
|
|
519
|
+
### Screen Reader Support
|
|
520
|
+
|
|
521
|
+
```tsx
|
|
522
|
+
<Select
|
|
523
|
+
label="Country"
|
|
524
|
+
helperText="Select your country of residence"
|
|
525
|
+
options={countries}
|
|
526
|
+
aria-label="Country selection"
|
|
527
|
+
/>
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Form Association
|
|
531
|
+
|
|
532
|
+
```tsx
|
|
533
|
+
<FormControl required error={hasError}>
|
|
534
|
+
<FormLabel>Country</FormLabel>
|
|
535
|
+
<Select options={countries} />
|
|
536
|
+
<FormHelperText>{hasError ? 'Please select a country' : 'Required field'}</FormHelperText>
|
|
537
|
+
</FormControl>
|
|
538
|
+
```
|
|
539
|
+
|
|
491
540
|
## Best Practices
|
|
492
541
|
|
|
493
|
-
|
|
542
|
+
### ✅ Do
|
|
543
|
+
|
|
544
|
+
1. **Use clear labels**: Labels should clearly describe what the user is selecting
|
|
494
545
|
|
|
495
546
|
```tsx
|
|
496
|
-
// ✅ Good
|
|
547
|
+
// ✅ Good: Clear, specific label
|
|
497
548
|
<Select label="Preferred contact method" options={contactMethods} />
|
|
498
549
|
|
|
499
|
-
// ❌ Bad
|
|
550
|
+
// ❌ Bad: Vague label
|
|
500
551
|
<Select label="Select" options={contactMethods} />
|
|
501
552
|
```
|
|
502
553
|
|
|
503
|
-
2. **Provide meaningful option
|
|
554
|
+
2. **Provide meaningful option labels**: Options should be easy to understand
|
|
504
555
|
|
|
505
556
|
```tsx
|
|
506
|
-
// ✅ Good
|
|
557
|
+
// ✅ Good: Descriptive options
|
|
507
558
|
{ value: 'express', label: 'Express Shipping (1-2 days)' }
|
|
508
559
|
|
|
509
|
-
// ❌ Bad
|
|
560
|
+
// ❌ Bad: Cryptic options
|
|
510
561
|
{ value: 'exp', label: 'EXP' }
|
|
511
562
|
```
|
|
512
563
|
|
|
513
|
-
3. **
|
|
564
|
+
3. **Order options logically**: Alphabetically, by frequency, or by importance
|
|
565
|
+
|
|
566
|
+
4. **Include a placeholder**: Help users understand what to select
|
|
567
|
+
|
|
568
|
+
```tsx
|
|
569
|
+
<Select placeholder="Select a country..." options={countries} />
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
5. **Use helper text**: Provide additional context when needed
|
|
514
573
|
|
|
515
574
|
```tsx
|
|
516
|
-
// ✅ Good: Select for data
|
|
517
575
|
<Select
|
|
518
|
-
label="
|
|
519
|
-
|
|
576
|
+
label="Timezone"
|
|
577
|
+
helperText="Select the timezone for your reports"
|
|
578
|
+
options={timezones}
|
|
520
579
|
/>
|
|
580
|
+
```
|
|
521
581
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
582
|
+
### ❌ Don't
|
|
583
|
+
|
|
584
|
+
1. **Don't use for actions**: Select is for data, not navigation or actions
|
|
585
|
+
|
|
586
|
+
```tsx
|
|
587
|
+
// ❌ Bad: Using Select for actions
|
|
588
|
+
<Select options={[
|
|
589
|
+
{ value: 'edit', label: 'Edit' },
|
|
590
|
+
{ value: 'delete', label: 'Delete' },
|
|
591
|
+
]} />
|
|
592
|
+
|
|
593
|
+
// ✅ Good: Use Dropdown for actions
|
|
594
|
+
<Dropdown>
|
|
595
|
+
<MenuButton>Actions</MenuButton>
|
|
596
|
+
<Menu>
|
|
597
|
+
<MenuItem onClick={handleEdit}>Edit</MenuItem>
|
|
598
|
+
<MenuItem onClick={handleDelete}>Delete</MenuItem>
|
|
599
|
+
</Menu>
|
|
600
|
+
</Dropdown>
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
2. **Don't disable without explanation**: If options are unavailable, explain why
|
|
604
|
+
|
|
605
|
+
3. **Don't use with very few options**: Consider RadioGroup for 2-4 options
|
|
606
|
+
|
|
607
|
+
4. **Don't use with many options without search**: Use Autocomplete for 20+ options
|
|
608
|
+
|
|
609
|
+
## Performance Considerations
|
|
610
|
+
|
|
611
|
+
### Large Option Lists
|
|
612
|
+
|
|
613
|
+
For lists with many options, consider:
|
|
614
|
+
|
|
615
|
+
1. **Pagination or virtual scrolling**: For very large lists
|
|
616
|
+
2. **Autocomplete**: When users need to search through options
|
|
617
|
+
3. **Lazy loading**: Load options on demand
|
|
618
|
+
|
|
619
|
+
```tsx
|
|
620
|
+
// For many options, use Autocomplete instead
|
|
621
|
+
<Autocomplete
|
|
622
|
+
options={largeOptionList}
|
|
623
|
+
getOptionLabel={(option) => option.label}
|
|
624
|
+
renderInput={(params) => <Input {...params} label="Search..." />}
|
|
528
625
|
/>
|
|
529
626
|
```
|
|
530
627
|
|
|
531
|
-
|
|
628
|
+
### Controlled vs Uncontrolled
|
|
532
629
|
|
|
533
|
-
|
|
630
|
+
Use controlled mode only when necessary:
|
|
534
631
|
|
|
535
632
|
```tsx
|
|
536
|
-
//
|
|
537
|
-
<Select
|
|
633
|
+
// Uncontrolled - simpler, better performance
|
|
634
|
+
<Select defaultValue="option1" options={options} />
|
|
538
635
|
|
|
539
|
-
//
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
<Select options={timezones} />
|
|
543
|
-
<FormHelperText>Used for report scheduling</FormHelperText>
|
|
544
|
-
</FormControl>
|
|
636
|
+
// Controlled - when you need to sync with other state
|
|
637
|
+
const [value, setValue] = useState('option1');
|
|
638
|
+
<Select value={value} onChange={(e, val) => setValue(val)} options={options} />
|
|
545
639
|
```
|
|
546
640
|
|
|
547
|
-
|
|
641
|
+
### Memoize Options
|
|
642
|
+
|
|
643
|
+
When options are computed, memoize them:
|
|
644
|
+
|
|
645
|
+
```tsx
|
|
646
|
+
const options = useMemo(() =>
|
|
647
|
+
data.map(item => ({
|
|
648
|
+
value: item.id,
|
|
649
|
+
label: item.name,
|
|
650
|
+
})),
|
|
651
|
+
[data]);
|
|
652
|
+
|
|
653
|
+
<Select options={options} />
|
|
654
|
+
```
|
|
548
655
|
|
|
549
|
-
|
|
550
|
-
- **Keyboard navigation**: The select can be opened with Enter or Space, navigated with Arrow Up/Down and Home/End, confirmed with Enter, and dismissed with Escape.
|
|
551
|
-
- **Error announcement**: When `error` is set, `aria-invalid` is applied. Pair it with a descriptive `helperText` so assistive technology can announce the error reason.
|
|
552
|
-
- **Required state**: The `required` prop adds `aria-required` and a visible asterisk to the label, communicating the requirement both visually and programmatically.
|
|
656
|
+
Select is a fundamental form component that provides a clean interface for choosing from predefined options. Use it appropriately to create intuitive forms and ensure users can easily make selections.
|