@coinbase/cds-mcp-server 8.19.1 → 8.20.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/CHANGELOG.md +8 -0
- package/mcp-docs/mobile/components/AvatarButton.txt +1 -1
- package/mcp-docs/mobile/components/Button.txt +1 -1
- package/mcp-docs/mobile/components/CheckboxCell.txt +1 -1
- package/mcp-docs/mobile/components/Chip.txt +2 -1
- package/mcp-docs/mobile/components/ContentCell.txt +1 -0
- package/mcp-docs/mobile/components/IconButton.txt +1 -1
- package/mcp-docs/mobile/components/InputChip.txt +7 -3
- package/mcp-docs/mobile/components/Interactable.txt +1 -1
- package/mcp-docs/mobile/components/ListCell.txt +1 -0
- package/mcp-docs/mobile/components/MediaChip.txt +2 -1
- package/mcp-docs/mobile/components/Pressable.txt +1 -1
- package/mcp-docs/mobile/components/RadioCell.txt +1 -1
- package/mcp-docs/mobile/components/Select.txt +12 -12
- package/mcp-docs/mobile/components/SelectAlpha.txt +1211 -0
- package/mcp-docs/mobile/components/SelectChip.txt +2 -1
- package/mcp-docs/mobile/components/SelectOption.txt +3 -2
- package/mcp-docs/mobile/components/SlideButton.txt +1 -1
- package/mcp-docs/mobile/routes.txt +1 -0
- package/mcp-docs/web/components/AvatarButton.txt +1 -1
- package/mcp-docs/web/components/Button.txt +1 -1
- package/mcp-docs/web/components/CheckboxCell.txt +1 -1
- package/mcp-docs/web/components/Chip.txt +2 -2
- package/mcp-docs/web/components/IconButton.txt +1 -1
- package/mcp-docs/web/components/InputChip.txt +7 -2
- package/mcp-docs/web/components/Interactable.txt +1 -1
- package/mcp-docs/web/components/Link.txt +1 -1
- package/mcp-docs/web/components/MediaChip.txt +2 -2
- package/mcp-docs/web/components/Pressable.txt +1 -1
- package/mcp-docs/web/components/RadioCell.txt +1 -1
- package/mcp-docs/web/components/Select.txt +16 -16
- package/mcp-docs/web/components/SelectAlpha.txt +1115 -0
- package/mcp-docs/web/components/SelectChip.txt +3 -2
- package/mcp-docs/web/components/SelectOption.txt +2 -2
- package/mcp-docs/web/components/SidebarItem.txt +1 -1
- package/mcp-docs/web/components/TileButton.txt +1 -1
- package/mcp-docs/web/routes.txt +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,1211 @@
|
|
|
1
|
+
# SelectAlpha
|
|
2
|
+
|
|
3
|
+
A flexible select component for both single and multi-selection, built for mobile applications with comprehensive accessibility support.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Select } from '@coinbase/cds-mobile/alpha/select'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Examples
|
|
12
|
+
|
|
13
|
+
### Single Select
|
|
14
|
+
|
|
15
|
+
Basic single selection with predefined options for mobile interfaces.
|
|
16
|
+
|
|
17
|
+
```jsx
|
|
18
|
+
function SingleSelectExample() {
|
|
19
|
+
const [value, setValue] = useState('1');
|
|
20
|
+
|
|
21
|
+
const options = [
|
|
22
|
+
{ value: '1', label: 'Option 1' },
|
|
23
|
+
{ value: '2', label: 'Option 2' },
|
|
24
|
+
{ value: '3', label: 'Option 3' },
|
|
25
|
+
{ value: '4', label: 'Option 4' },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Select
|
|
30
|
+
label="Choose an option"
|
|
31
|
+
value={value}
|
|
32
|
+
onChange={setValue}
|
|
33
|
+
options={options}
|
|
34
|
+
placeholder="Select an option"
|
|
35
|
+
/>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Multi-Select
|
|
41
|
+
|
|
42
|
+
Multi-selection mode allows users to select multiple options from the list with touch-friendly controls.
|
|
43
|
+
|
|
44
|
+
```jsx
|
|
45
|
+
function MultiSelectExample() {
|
|
46
|
+
const { value, onChange } = useMultiSelect({
|
|
47
|
+
initialValue: ['1', '3'],
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const options = [
|
|
51
|
+
{ value: '1', label: 'Option 1' },
|
|
52
|
+
{ value: '2', label: 'Option 2' },
|
|
53
|
+
{ value: '3', label: 'Option 3' },
|
|
54
|
+
{ value: '4', label: 'Option 4' },
|
|
55
|
+
{ value: '5', label: 'Option 5' },
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
return (
|
|
59
|
+
<Select
|
|
60
|
+
type="multi"
|
|
61
|
+
label="Choose multiple options"
|
|
62
|
+
value={value}
|
|
63
|
+
onChange={onChange}
|
|
64
|
+
options={options}
|
|
65
|
+
placeholder="Select options"
|
|
66
|
+
selectAllLabel="Select all options"
|
|
67
|
+
clearAllLabel="Clear all selections"
|
|
68
|
+
/>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Accessibility Props
|
|
74
|
+
|
|
75
|
+
The mobile Select component supports comprehensive accessibility features including custom labels, hints, and roles.
|
|
76
|
+
|
|
77
|
+
```jsx
|
|
78
|
+
function AccessibilityExample() {
|
|
79
|
+
const [value, setValue] = useState('2');
|
|
80
|
+
|
|
81
|
+
const options = [
|
|
82
|
+
{ value: '1', label: 'High Priority' },
|
|
83
|
+
{ value: '2', label: 'Medium Priority' },
|
|
84
|
+
{ value: '3', label: 'Low Priority' },
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<Select
|
|
89
|
+
label="Task Priority"
|
|
90
|
+
value={value}
|
|
91
|
+
onChange={setValue}
|
|
92
|
+
options={options}
|
|
93
|
+
accessibilityLabel="Select task priority level"
|
|
94
|
+
accessibilityHint="Choose the appropriate priority for this task"
|
|
95
|
+
accessibilityRoles={{
|
|
96
|
+
option: 'button',
|
|
97
|
+
}}
|
|
98
|
+
placeholder="Choose priority level"
|
|
99
|
+
helperText="Select the appropriate priority for this task"
|
|
100
|
+
/>
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Variant Props
|
|
106
|
+
|
|
107
|
+
The mobile Select component supports different visual variants for various states and contexts.
|
|
108
|
+
|
|
109
|
+
```jsx
|
|
110
|
+
function VariantExample() {
|
|
111
|
+
const [positiveValue, setPositiveValue] = useState('success');
|
|
112
|
+
const [negativeValue, setNegativeValue] = useState('');
|
|
113
|
+
|
|
114
|
+
const positiveOptions = [
|
|
115
|
+
{ value: 'success', label: 'Success' },
|
|
116
|
+
{ value: 'completed', label: 'Completed' },
|
|
117
|
+
{ value: 'approved', label: 'Approved' },
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
const negativeOptions = [
|
|
121
|
+
{ value: 'error', label: 'Error' },
|
|
122
|
+
{ value: 'failed', label: 'Failed' },
|
|
123
|
+
{ value: 'rejected', label: 'Rejected' },
|
|
124
|
+
];
|
|
125
|
+
|
|
126
|
+
return (
|
|
127
|
+
<VStack gap={4}>
|
|
128
|
+
<Select
|
|
129
|
+
label="Positive Status"
|
|
130
|
+
value={positiveValue}
|
|
131
|
+
onChange={setPositiveValue}
|
|
132
|
+
options={positiveOptions}
|
|
133
|
+
variant="positive"
|
|
134
|
+
helperText="This shows a positive state"
|
|
135
|
+
placeholder="Select positive status"
|
|
136
|
+
/>
|
|
137
|
+
|
|
138
|
+
<Select
|
|
139
|
+
label="Negative Status"
|
|
140
|
+
value={negativeValue}
|
|
141
|
+
onChange={setNegativeValue}
|
|
142
|
+
options={negativeOptions}
|
|
143
|
+
variant="negative"
|
|
144
|
+
helperText="This shows an error state"
|
|
145
|
+
placeholder="Select negative status"
|
|
146
|
+
/>
|
|
147
|
+
</VStack>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Compact Mode
|
|
153
|
+
|
|
154
|
+
The Select component can be rendered in a compact size for denser mobile UIs.
|
|
155
|
+
|
|
156
|
+
```jsx
|
|
157
|
+
function CompactExample() {
|
|
158
|
+
const [value, setValue] = useState('1');
|
|
159
|
+
|
|
160
|
+
const options = [
|
|
161
|
+
{ value: '1', label: 'Small Option 1' },
|
|
162
|
+
{ value: '2', label: 'Small Option 2' },
|
|
163
|
+
{ value: '3', label: 'Small Option 3' },
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<Select
|
|
168
|
+
compact
|
|
169
|
+
label="Compact Select"
|
|
170
|
+
value={value}
|
|
171
|
+
onChange={setValue}
|
|
172
|
+
options={options}
|
|
173
|
+
placeholder="Select an option"
|
|
174
|
+
helperText="This is a compact select component"
|
|
175
|
+
/>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Disabled States
|
|
181
|
+
|
|
182
|
+
Components can be disabled entirely or have individual options disabled.
|
|
183
|
+
|
|
184
|
+
```jsx
|
|
185
|
+
function DisabledExample() {
|
|
186
|
+
const [value1, setValue1] = useState('2');
|
|
187
|
+
const [value2, setValue2] = useState('2');
|
|
188
|
+
|
|
189
|
+
const optionsWithDisabled = [
|
|
190
|
+
{ value: '1', label: 'Option 1', disabled: true },
|
|
191
|
+
{ value: '2', label: 'Option 2' },
|
|
192
|
+
{ value: '3', label: 'Option 3' },
|
|
193
|
+
{ value: '4', label: 'Option 4', disabled: true },
|
|
194
|
+
];
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<VStack gap={4}>
|
|
198
|
+
<Select
|
|
199
|
+
label="Disabled Select"
|
|
200
|
+
value={value1}
|
|
201
|
+
onChange={setValue1}
|
|
202
|
+
options={optionsWithDisabled}
|
|
203
|
+
disabled
|
|
204
|
+
placeholder="This select is disabled"
|
|
205
|
+
/>
|
|
206
|
+
|
|
207
|
+
<Select
|
|
208
|
+
label="Select with Disabled Options"
|
|
209
|
+
value={value2}
|
|
210
|
+
onChange={setValue2}
|
|
211
|
+
options={optionsWithDisabled}
|
|
212
|
+
placeholder="Some options are disabled"
|
|
213
|
+
/>
|
|
214
|
+
</VStack>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Options with Descriptions
|
|
220
|
+
|
|
221
|
+
Options can include descriptions for additional context, perfect for mobile interfaces.
|
|
222
|
+
|
|
223
|
+
```jsx
|
|
224
|
+
function DescriptionExample() {
|
|
225
|
+
const [value, setValue] = useState('1');
|
|
226
|
+
|
|
227
|
+
const optionsWithDescriptions = [
|
|
228
|
+
{ value: '1', label: 'Bitcoin', description: 'The first cryptocurrency' },
|
|
229
|
+
{ value: '2', label: 'Ethereum', description: 'Smart contract platform' },
|
|
230
|
+
{ value: '3', label: 'USDC', description: 'USD-backed stablecoin' },
|
|
231
|
+
{ value: '4', label: 'Solana', description: 'High-performance blockchain' },
|
|
232
|
+
];
|
|
233
|
+
|
|
234
|
+
return (
|
|
235
|
+
<Select
|
|
236
|
+
label="Select Cryptocurrency"
|
|
237
|
+
value={value}
|
|
238
|
+
onChange={setValue}
|
|
239
|
+
options={optionsWithDescriptions}
|
|
240
|
+
placeholder="Choose a cryptocurrency"
|
|
241
|
+
/>
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Start Node
|
|
247
|
+
|
|
248
|
+
Add an icon or element at the start of the select control for better visual context.
|
|
249
|
+
|
|
250
|
+
```jsx
|
|
251
|
+
function StartNodeExample() {
|
|
252
|
+
const [value, setValue] = useState('1');
|
|
253
|
+
|
|
254
|
+
const options = [
|
|
255
|
+
{ value: '1', label: 'Search Result 1' },
|
|
256
|
+
{ value: '2', label: 'Search Result 2' },
|
|
257
|
+
{ value: '3', label: 'Search Result 3' },
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
return (
|
|
261
|
+
<Select
|
|
262
|
+
label="Search"
|
|
263
|
+
value={value}
|
|
264
|
+
onChange={setValue}
|
|
265
|
+
options={options}
|
|
266
|
+
startNode={<Icon color="fg" name="search" />}
|
|
267
|
+
placeholder="Search for options"
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### End Node
|
|
274
|
+
|
|
275
|
+
Add an icon or element at the end of the select control.
|
|
276
|
+
|
|
277
|
+
```jsx
|
|
278
|
+
function EndNodeExample() {
|
|
279
|
+
const [value, setValue] = useState('1');
|
|
280
|
+
|
|
281
|
+
const options = [
|
|
282
|
+
{ value: '1', label: 'Search Result 1' },
|
|
283
|
+
{ value: '2', label: 'Search Result 2' },
|
|
284
|
+
{ value: '3', label: 'Search Result 3' },
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
return (
|
|
288
|
+
<Select
|
|
289
|
+
endNode={<Icon color="fg" name="search" />}
|
|
290
|
+
label="Single select - custom end node"
|
|
291
|
+
onChange={setValue}
|
|
292
|
+
options={options}
|
|
293
|
+
placeholder="Empty value"
|
|
294
|
+
value={value}
|
|
295
|
+
/>
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Custom Icons
|
|
301
|
+
|
|
302
|
+
Add custom icons as accessories or media to options for enhanced visual hierarchy.
|
|
303
|
+
|
|
304
|
+
```jsx
|
|
305
|
+
function CustomIconsExample() {
|
|
306
|
+
const [value, setValue] = useState('1');
|
|
307
|
+
|
|
308
|
+
const optionsWithIcons = [
|
|
309
|
+
{
|
|
310
|
+
value: '1',
|
|
311
|
+
label: 'Favorites',
|
|
312
|
+
accessory: <Icon color="fg" name="star" />,
|
|
313
|
+
media: <Icon color="fg" name="heart" />,
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
value: '2',
|
|
317
|
+
label: 'Verified',
|
|
318
|
+
accessory: <Icon color="fg" name="checkmark" />,
|
|
319
|
+
media: <Icon color="fg" name="search" />,
|
|
320
|
+
},
|
|
321
|
+
{
|
|
322
|
+
value: '3',
|
|
323
|
+
label: 'Settings',
|
|
324
|
+
accessory: <Icon color="fg" name="caretRight" />,
|
|
325
|
+
media: <Icon color="fg" name="gear" />,
|
|
326
|
+
},
|
|
327
|
+
];
|
|
328
|
+
|
|
329
|
+
return (
|
|
330
|
+
<Select
|
|
331
|
+
label="Choose Action"
|
|
332
|
+
value={value}
|
|
333
|
+
onChange={setValue}
|
|
334
|
+
options={optionsWithIcons}
|
|
335
|
+
placeholder="Select an action"
|
|
336
|
+
/>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Empty State
|
|
342
|
+
|
|
343
|
+
Handle empty option lists with custom messages optimized for mobile screens.
|
|
344
|
+
|
|
345
|
+
```jsx
|
|
346
|
+
function EmptyStateExample() {
|
|
347
|
+
const [value, setValue] = useState(null);
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<VStack gap={4}>
|
|
351
|
+
<Select
|
|
352
|
+
label="Empty Options"
|
|
353
|
+
value={value}
|
|
354
|
+
onChange={setValue}
|
|
355
|
+
options={[]}
|
|
356
|
+
emptyOptionsLabel="No options available at this time"
|
|
357
|
+
placeholder="No options"
|
|
358
|
+
/>
|
|
359
|
+
|
|
360
|
+
<Select
|
|
361
|
+
label="Custom Empty Component"
|
|
362
|
+
value={value}
|
|
363
|
+
onChange={setValue}
|
|
364
|
+
options={[]}
|
|
365
|
+
SelectEmptyOptionsComponent={
|
|
366
|
+
<Text background="fgWarning" font="headline" padding={4}>
|
|
367
|
+
No items found. Try refreshing!
|
|
368
|
+
</Text>
|
|
369
|
+
}
|
|
370
|
+
placeholder="No options"
|
|
371
|
+
/>
|
|
372
|
+
</VStack>
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Long Labels
|
|
378
|
+
|
|
379
|
+
Handle very long option labels that may wrap on smaller mobile screens.
|
|
380
|
+
|
|
381
|
+
```jsx
|
|
382
|
+
function LongLabelsExample() {
|
|
383
|
+
const [value, setValue] = useState('1');
|
|
384
|
+
|
|
385
|
+
const longOptions = [
|
|
386
|
+
{
|
|
387
|
+
value: '1',
|
|
388
|
+
label:
|
|
389
|
+
'This is an extremely long option label that should test how the component handles very long text content on mobile devices',
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
value: '2',
|
|
393
|
+
label:
|
|
394
|
+
'Another super long option label with even more text to see how it wraps or truncates in the mobile UI',
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
value: '3',
|
|
398
|
+
label: 'Short',
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
value: '4',
|
|
402
|
+
label: 'A moderately long label that is somewhere between short and extremely long',
|
|
403
|
+
},
|
|
404
|
+
];
|
|
405
|
+
|
|
406
|
+
return (
|
|
407
|
+
<Select
|
|
408
|
+
label="Select with Long Labels"
|
|
409
|
+
value={value}
|
|
410
|
+
onChange={setValue}
|
|
411
|
+
options={longOptions}
|
|
412
|
+
placeholder="Choose an option"
|
|
413
|
+
/>
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
```
|
|
417
|
+
|
|
418
|
+
### Multi-Select with Max Display
|
|
419
|
+
|
|
420
|
+
Limit the number of selected items shown when using multi-select on mobile.
|
|
421
|
+
|
|
422
|
+
```jsx
|
|
423
|
+
function MaxDisplayExample() {
|
|
424
|
+
const { value, onChange } = useMultiSelect({
|
|
425
|
+
initialValue: ['1', '2', '3', '4', '5'],
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
const options = Array.from({ length: 20 }, (_, i) => ({
|
|
429
|
+
value: (i + 1).toString(),
|
|
430
|
+
label: `Option ${i + 1}`,
|
|
431
|
+
}));
|
|
432
|
+
|
|
433
|
+
return (
|
|
434
|
+
<Select
|
|
435
|
+
type="multi"
|
|
436
|
+
label="Select Multiple Items"
|
|
437
|
+
value={value}
|
|
438
|
+
onChange={onChange}
|
|
439
|
+
options={options}
|
|
440
|
+
maxSelectedOptionsToShow={3}
|
|
441
|
+
placeholder="Select options"
|
|
442
|
+
helperText="Showing first 3 selected items"
|
|
443
|
+
/>
|
|
444
|
+
);
|
|
445
|
+
}
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Custom Select All labels
|
|
449
|
+
|
|
450
|
+
Customize the select all functionality in multi-select mode for mobile.
|
|
451
|
+
|
|
452
|
+
```jsx
|
|
453
|
+
function CustomSelectAllExample() {
|
|
454
|
+
const { value, onChange } = useMultiSelect({
|
|
455
|
+
initialValue: ['1'],
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
const options = [
|
|
459
|
+
{ value: '1', label: 'Monday' },
|
|
460
|
+
{ value: '2', label: 'Tuesday' },
|
|
461
|
+
{ value: '3', label: 'Wednesday' },
|
|
462
|
+
{ value: '4', label: 'Thursday' },
|
|
463
|
+
{ value: '5', label: 'Friday' },
|
|
464
|
+
{ value: '6', label: 'Saturday' },
|
|
465
|
+
{ value: '7', label: 'Sunday' },
|
|
466
|
+
];
|
|
467
|
+
|
|
468
|
+
return (
|
|
469
|
+
<Select
|
|
470
|
+
type="multi"
|
|
471
|
+
label="Select Days"
|
|
472
|
+
value={value}
|
|
473
|
+
onChange={onChange}
|
|
474
|
+
options={options}
|
|
475
|
+
selectAllLabel="Select all days of the week"
|
|
476
|
+
clearAllLabel="Clear all days"
|
|
477
|
+
placeholder="Choose days"
|
|
478
|
+
/>
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### Hide Select All
|
|
484
|
+
|
|
485
|
+
Hide the select all option for simpler multi-select interfaces.
|
|
486
|
+
|
|
487
|
+
```jsx
|
|
488
|
+
function HideSelectAllExample() {
|
|
489
|
+
const { value, onChange } = useMultiSelect({
|
|
490
|
+
initialValue: ['1', '2'],
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
const options = [
|
|
494
|
+
{ value: '1', label: 'Option 1' },
|
|
495
|
+
{ value: '2', label: 'Option 2' },
|
|
496
|
+
{ value: '3', label: 'Option 3' },
|
|
497
|
+
{ value: '4', label: 'Option 4' },
|
|
498
|
+
{ value: '5', label: 'Option 5' },
|
|
499
|
+
];
|
|
500
|
+
|
|
501
|
+
return (
|
|
502
|
+
<Select
|
|
503
|
+
type="multi"
|
|
504
|
+
hideSelectAll
|
|
505
|
+
label="Multi-Select without Select All"
|
|
506
|
+
value={value}
|
|
507
|
+
onChange={onChange}
|
|
508
|
+
options={options}
|
|
509
|
+
placeholder="Choose options"
|
|
510
|
+
/>
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
### Combined Features
|
|
516
|
+
|
|
517
|
+
Example combining multiple features for a rich mobile experience.
|
|
518
|
+
|
|
519
|
+
```jsx
|
|
520
|
+
function CombinedFeaturesExample() {
|
|
521
|
+
const [value, setValue] = useState('1');
|
|
522
|
+
|
|
523
|
+
const options = [
|
|
524
|
+
{
|
|
525
|
+
value: '1',
|
|
526
|
+
label: 'Premium Account',
|
|
527
|
+
description: 'Access to all features',
|
|
528
|
+
accessory: <Icon color="fg" name="star" />,
|
|
529
|
+
media: <Icon color="fg" name="search" />,
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
value: '2',
|
|
533
|
+
label: 'Standard Account',
|
|
534
|
+
description: 'Basic features included',
|
|
535
|
+
media: <Icon color="fg" name="search" />,
|
|
536
|
+
},
|
|
537
|
+
{
|
|
538
|
+
value: '3',
|
|
539
|
+
label: 'Trial Account',
|
|
540
|
+
description: 'Limited time access',
|
|
541
|
+
disabled: true,
|
|
542
|
+
media: <Icon color="fg" name="clock" />,
|
|
543
|
+
},
|
|
544
|
+
];
|
|
545
|
+
|
|
546
|
+
return (
|
|
547
|
+
<Select
|
|
548
|
+
label="Account Type"
|
|
549
|
+
value={value}
|
|
550
|
+
onChange={setValue}
|
|
551
|
+
options={options}
|
|
552
|
+
startNode={<Icon color="fg" name="filter" />}
|
|
553
|
+
variant="positive"
|
|
554
|
+
helperText="Choose your account type"
|
|
555
|
+
placeholder="Select account"
|
|
556
|
+
/>
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
### Options with Only Description
|
|
562
|
+
|
|
563
|
+
Options that display only descriptions without labels.
|
|
564
|
+
|
|
565
|
+
```jsx
|
|
566
|
+
function OnlyDescriptionExample() {
|
|
567
|
+
const [value, setValue] = useState('1');
|
|
568
|
+
|
|
569
|
+
const descriptionOnlyOptions = [
|
|
570
|
+
{ value: '1', description: 'First description without a label' },
|
|
571
|
+
{ value: '2', description: 'Second description only' },
|
|
572
|
+
{ value: '3', description: 'Third item with just description' },
|
|
573
|
+
{ value: '4', description: 'Fourth description-only option' },
|
|
574
|
+
];
|
|
575
|
+
|
|
576
|
+
return (
|
|
577
|
+
<Select
|
|
578
|
+
label="Description-Only Options"
|
|
579
|
+
value={value}
|
|
580
|
+
onChange={setValue}
|
|
581
|
+
options={descriptionOnlyOptions}
|
|
582
|
+
placeholder="Select by description"
|
|
583
|
+
/>
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
### No Visible Label
|
|
589
|
+
|
|
590
|
+
Select without a visible label (accessibility label/hint still required).
|
|
591
|
+
|
|
592
|
+
```jsx
|
|
593
|
+
function NoLabelExample() {
|
|
594
|
+
const [value, setValue] = useState('1');
|
|
595
|
+
|
|
596
|
+
const options = [
|
|
597
|
+
{ value: '1', label: 'Option 1' },
|
|
598
|
+
{ value: '2', label: 'Option 2' },
|
|
599
|
+
{ value: '3', label: 'Option 3' },
|
|
600
|
+
];
|
|
601
|
+
|
|
602
|
+
return (
|
|
603
|
+
<Select
|
|
604
|
+
accessibilityLabel="Hidden label select"
|
|
605
|
+
accessibilityHint="This select has no visible label"
|
|
606
|
+
value={value}
|
|
607
|
+
onChange={setValue}
|
|
608
|
+
options={options}
|
|
609
|
+
placeholder="Select without visible label"
|
|
610
|
+
/>
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
### Mixed Option Types
|
|
616
|
+
|
|
617
|
+
Options with varying properties in the same select.
|
|
618
|
+
|
|
619
|
+
```jsx
|
|
620
|
+
function MixedOptionsExample() {
|
|
621
|
+
const [value, setValue] = useState('1');
|
|
622
|
+
|
|
623
|
+
const mixedOptions = [
|
|
624
|
+
{ value: '1', label: 'Bitcoin', description: 'The original cryptocurrency' },
|
|
625
|
+
{ value: '2', label: 'Ethereum' },
|
|
626
|
+
{ value: '3', label: 'USDC', description: 'USD-backed stablecoin' },
|
|
627
|
+
{ value: '4', label: 'Solana' },
|
|
628
|
+
{ value: '5', label: 'Polygon', description: 'Layer 2 scaling solution' },
|
|
629
|
+
];
|
|
630
|
+
|
|
631
|
+
return (
|
|
632
|
+
<Select
|
|
633
|
+
label="Mixed Option Types"
|
|
634
|
+
value={value}
|
|
635
|
+
onChange={setValue}
|
|
636
|
+
options={mixedOptions}
|
|
637
|
+
placeholder="Choose an asset"
|
|
638
|
+
/>
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
### Variant Combinations
|
|
644
|
+
|
|
645
|
+
Combine compact mode with different variants.
|
|
646
|
+
|
|
647
|
+
```jsx
|
|
648
|
+
function VariantCombinationsExample() {
|
|
649
|
+
const [value1, setValue1] = useState('1');
|
|
650
|
+
const [value2, setValue2] = useState('2');
|
|
651
|
+
|
|
652
|
+
const options = [
|
|
653
|
+
{ value: '1', label: 'Option 1' },
|
|
654
|
+
{ value: '2', label: 'Option 2' },
|
|
655
|
+
{ value: '3', label: 'Option 3' },
|
|
656
|
+
];
|
|
657
|
+
|
|
658
|
+
return (
|
|
659
|
+
<VStack gap={4}>
|
|
660
|
+
<Select
|
|
661
|
+
compact
|
|
662
|
+
variant="positive"
|
|
663
|
+
label="Compact + Positive"
|
|
664
|
+
value={value1}
|
|
665
|
+
onChange={setValue1}
|
|
666
|
+
options={options}
|
|
667
|
+
helperText="Success state in compact mode"
|
|
668
|
+
/>
|
|
669
|
+
|
|
670
|
+
<Select
|
|
671
|
+
compact
|
|
672
|
+
variant="negative"
|
|
673
|
+
label="Compact + Negative"
|
|
674
|
+
value={value2}
|
|
675
|
+
onChange={setValue2}
|
|
676
|
+
options={options}
|
|
677
|
+
helperText="Error state in compact mode"
|
|
678
|
+
/>
|
|
679
|
+
</VStack>
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
### Multi-Select with Descriptions
|
|
685
|
+
|
|
686
|
+
Multi-select mode with descriptive options.
|
|
687
|
+
|
|
688
|
+
```jsx
|
|
689
|
+
function MultiSelectWithDescriptionsExample() {
|
|
690
|
+
const { value, onChange } = useMultiSelect({
|
|
691
|
+
initialValue: ['1', '2'],
|
|
692
|
+
});
|
|
693
|
+
|
|
694
|
+
const optionsWithDescriptions = [
|
|
695
|
+
{ value: '1', label: 'Push Notifications', description: 'Get alerts on your device' },
|
|
696
|
+
{ value: '2', label: 'Email Updates', description: 'Weekly newsletter' },
|
|
697
|
+
{ value: '3', label: 'SMS Alerts', description: 'Text message notifications' },
|
|
698
|
+
{ value: '4', label: 'In-App Messages', description: 'Messages within the app' },
|
|
699
|
+
];
|
|
700
|
+
|
|
701
|
+
return (
|
|
702
|
+
<Select
|
|
703
|
+
type="multi"
|
|
704
|
+
label="Notification Preferences"
|
|
705
|
+
value={value}
|
|
706
|
+
onChange={onChange}
|
|
707
|
+
options={optionsWithDescriptions}
|
|
708
|
+
placeholder="Select notification types"
|
|
709
|
+
/>
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
### Custom Styles
|
|
715
|
+
|
|
716
|
+
Apply custom styles to the Select component.
|
|
717
|
+
|
|
718
|
+
```jsx
|
|
719
|
+
function CustomStylesExample() {
|
|
720
|
+
const [value, setValue] = useState('1');
|
|
721
|
+
|
|
722
|
+
const options = [
|
|
723
|
+
{ value: '1', label: 'Custom Style 1' },
|
|
724
|
+
{ value: '2', label: 'Custom Style 2' },
|
|
725
|
+
{ value: '3', label: 'Custom Style 3' },
|
|
726
|
+
];
|
|
727
|
+
|
|
728
|
+
return (
|
|
729
|
+
<Select
|
|
730
|
+
label="Custom Styled Select"
|
|
731
|
+
value={value}
|
|
732
|
+
onChange={setValue}
|
|
733
|
+
options={options}
|
|
734
|
+
styles={{
|
|
735
|
+
control: {
|
|
736
|
+
backgroundColor: '#e8f4fd',
|
|
737
|
+
borderRadius: 12,
|
|
738
|
+
padding: 16,
|
|
739
|
+
},
|
|
740
|
+
option: {
|
|
741
|
+
backgroundColor: '#f0f8ff',
|
|
742
|
+
},
|
|
743
|
+
optionBlendStyles: {
|
|
744
|
+
pressedBackground: '#0066cc',
|
|
745
|
+
},
|
|
746
|
+
}}
|
|
747
|
+
placeholder="Styled select"
|
|
748
|
+
/>
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Custom Long Placeholder
|
|
754
|
+
|
|
755
|
+
Extended placeholder text for mobile screens.
|
|
756
|
+
|
|
757
|
+
```jsx
|
|
758
|
+
function LongPlaceholderExample() {
|
|
759
|
+
const [value, setValue] = useState(null);
|
|
760
|
+
|
|
761
|
+
const options = [
|
|
762
|
+
{ value: '1', label: 'Option 1' },
|
|
763
|
+
{ value: '2', label: 'Option 2' },
|
|
764
|
+
{ value: '3', label: 'Option 3' },
|
|
765
|
+
];
|
|
766
|
+
|
|
767
|
+
return (
|
|
768
|
+
<Select
|
|
769
|
+
label="Select with Long Placeholder"
|
|
770
|
+
value={value}
|
|
771
|
+
onChange={setValue}
|
|
772
|
+
options={options}
|
|
773
|
+
placeholder="This is a very long placeholder text that provides detailed instructions"
|
|
774
|
+
/>
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### Options with Only Accessory
|
|
780
|
+
|
|
781
|
+
Options with accessory icons only.
|
|
782
|
+
|
|
783
|
+
```jsx
|
|
784
|
+
function OnlyAccessoryExample() {
|
|
785
|
+
const [value, setValue] = useState('1');
|
|
786
|
+
|
|
787
|
+
const optionsWithAccessory = [
|
|
788
|
+
{
|
|
789
|
+
value: '1',
|
|
790
|
+
label: 'Starred',
|
|
791
|
+
accessory: <Icon color="fg" name="star" />,
|
|
792
|
+
},
|
|
793
|
+
{
|
|
794
|
+
value: '2',
|
|
795
|
+
label: 'Verified',
|
|
796
|
+
accessory: <Icon color="fg" name="checkmark" />,
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
value: '3',
|
|
800
|
+
label: 'Premium',
|
|
801
|
+
accessory: <Icon color="fg" name="search" />,
|
|
802
|
+
},
|
|
803
|
+
];
|
|
804
|
+
|
|
805
|
+
return (
|
|
806
|
+
<Select
|
|
807
|
+
label="Options with Accessories"
|
|
808
|
+
value={value}
|
|
809
|
+
onChange={setValue}
|
|
810
|
+
options={optionsWithAccessory}
|
|
811
|
+
placeholder="Select an option"
|
|
812
|
+
/>
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
### Options with Only Media
|
|
818
|
+
|
|
819
|
+
Options with media icons only.
|
|
820
|
+
|
|
821
|
+
```jsx
|
|
822
|
+
function OnlyMediaExample() {
|
|
823
|
+
const [value, setValue] = useState('1');
|
|
824
|
+
|
|
825
|
+
const optionsWithMedia = [
|
|
826
|
+
{
|
|
827
|
+
value: '1',
|
|
828
|
+
label: 'Home',
|
|
829
|
+
media: <Icon color="fg" name="home" />,
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
value: '2',
|
|
833
|
+
label: 'Profile',
|
|
834
|
+
media: <Icon color="fg" name="user" />,
|
|
835
|
+
},
|
|
836
|
+
{
|
|
837
|
+
value: '3',
|
|
838
|
+
label: 'Settings',
|
|
839
|
+
media: <Icon color="fg" name="gear" />,
|
|
840
|
+
},
|
|
841
|
+
];
|
|
842
|
+
|
|
843
|
+
return (
|
|
844
|
+
<Select
|
|
845
|
+
label="Navigation Options"
|
|
846
|
+
value={value}
|
|
847
|
+
onChange={setValue}
|
|
848
|
+
options={optionsWithMedia}
|
|
849
|
+
placeholder="Navigate to..."
|
|
850
|
+
/>
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
```
|
|
854
|
+
|
|
855
|
+
### Options as React Nodes
|
|
856
|
+
|
|
857
|
+
Options with custom React node labels and descriptions.
|
|
858
|
+
|
|
859
|
+
```jsx
|
|
860
|
+
function ReactNodeOptionsExample() {
|
|
861
|
+
const [value, setValue] = useState('1');
|
|
862
|
+
|
|
863
|
+
const reactNodeOptions = [
|
|
864
|
+
{
|
|
865
|
+
value: '1',
|
|
866
|
+
label: (
|
|
867
|
+
<Text font="title3" color="fgPrimary">
|
|
868
|
+
Bold Title 1
|
|
869
|
+
</Text>
|
|
870
|
+
),
|
|
871
|
+
description: (
|
|
872
|
+
<Text font="caption" color="fgSecondary">
|
|
873
|
+
Subtitle text 1
|
|
874
|
+
</Text>
|
|
875
|
+
),
|
|
876
|
+
},
|
|
877
|
+
{
|
|
878
|
+
value: '2',
|
|
879
|
+
label: (
|
|
880
|
+
<Text font="title3" color="fgPrimary">
|
|
881
|
+
Bold Title 2
|
|
882
|
+
</Text>
|
|
883
|
+
),
|
|
884
|
+
description: (
|
|
885
|
+
<Text font="caption" color="fgSecondary">
|
|
886
|
+
Subtitle text 2
|
|
887
|
+
</Text>
|
|
888
|
+
),
|
|
889
|
+
},
|
|
890
|
+
{
|
|
891
|
+
value: '3',
|
|
892
|
+
label: (
|
|
893
|
+
<Text font="title3" color="fgPrimary">
|
|
894
|
+
Bold Title 3
|
|
895
|
+
</Text>
|
|
896
|
+
),
|
|
897
|
+
description: (
|
|
898
|
+
<Text font="caption" color="fgSecondary">
|
|
899
|
+
Subtitle text 3
|
|
900
|
+
</Text>
|
|
901
|
+
),
|
|
902
|
+
},
|
|
903
|
+
];
|
|
904
|
+
|
|
905
|
+
return (
|
|
906
|
+
<Select
|
|
907
|
+
label="Custom Formatted Options"
|
|
908
|
+
value={value}
|
|
909
|
+
onChange={setValue}
|
|
910
|
+
options={reactNodeOptions}
|
|
911
|
+
placeholder="Select styled option"
|
|
912
|
+
/>
|
|
913
|
+
);
|
|
914
|
+
}
|
|
915
|
+
```
|
|
916
|
+
|
|
917
|
+
### Custom Select All Option
|
|
918
|
+
|
|
919
|
+
Customize the select all option component in multi-select.
|
|
920
|
+
|
|
921
|
+
```jsx
|
|
922
|
+
function CustomSelectAllOptionExample() {
|
|
923
|
+
const { value, onChange } = useMultiSelect({
|
|
924
|
+
initialValue: ['1'],
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
const CustomSelectAllOption = ({ onChange, selected, disabled, label, style }) => {
|
|
928
|
+
return (
|
|
929
|
+
<Pressable
|
|
930
|
+
background={selected ? 'bgPositive' : 'bg'}
|
|
931
|
+
disabled={disabled}
|
|
932
|
+
onPress={() => onChange('select-all')}
|
|
933
|
+
paddingX={3}
|
|
934
|
+
paddingY={4}
|
|
935
|
+
style={style}
|
|
936
|
+
>
|
|
937
|
+
<HStack gap={2} alignItems="center">
|
|
938
|
+
<Icon
|
|
939
|
+
color={selected ? 'fgPositive' : 'fg'}
|
|
940
|
+
name={selected ? 'circleCheckmark' : 'circle'}
|
|
941
|
+
/>
|
|
942
|
+
<Text color={selected ? 'fgPositive' : 'fg'} font="headline">
|
|
943
|
+
{String(label || 'Select Everything')}
|
|
944
|
+
</Text>
|
|
945
|
+
</HStack>
|
|
946
|
+
</Pressable>
|
|
947
|
+
);
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
const options = [
|
|
951
|
+
{ value: '1', label: 'Option 1' },
|
|
952
|
+
{ value: '2', label: 'Option 2' },
|
|
953
|
+
{ value: '3', label: 'Option 3' },
|
|
954
|
+
{ value: '4', label: 'Option 4' },
|
|
955
|
+
];
|
|
956
|
+
|
|
957
|
+
return (
|
|
958
|
+
<Select
|
|
959
|
+
type="multi"
|
|
960
|
+
SelectAllOptionComponent={CustomSelectAllOption}
|
|
961
|
+
label="Custom Select All"
|
|
962
|
+
value={value}
|
|
963
|
+
onChange={onChange}
|
|
964
|
+
options={options}
|
|
965
|
+
placeholder="Select options"
|
|
966
|
+
selectAllLabel="Pick All Items"
|
|
967
|
+
/>
|
|
968
|
+
);
|
|
969
|
+
}
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
### Edge Case Labels
|
|
973
|
+
|
|
974
|
+
Handle edge cases with empty or special character labels.
|
|
975
|
+
|
|
976
|
+
```jsx
|
|
977
|
+
function EdgeCaseLabelsExample() {
|
|
978
|
+
const [value, setValue] = useState('3');
|
|
979
|
+
|
|
980
|
+
const edgeOptions = [
|
|
981
|
+
{ value: '1', label: '' },
|
|
982
|
+
{ value: '2', label: ' ' },
|
|
983
|
+
{ value: '3', label: 'Normal Label' },
|
|
984
|
+
{ value: '4', label: '\t\n' },
|
|
985
|
+
{ value: '5', label: '🚀🌟💫' },
|
|
986
|
+
{ value: '6', label: '©™®' },
|
|
987
|
+
];
|
|
988
|
+
|
|
989
|
+
return (
|
|
990
|
+
<Select
|
|
991
|
+
label="Edge Case Labels"
|
|
992
|
+
value={value}
|
|
993
|
+
onChange={setValue}
|
|
994
|
+
options={edgeOptions}
|
|
995
|
+
placeholder="Select an option"
|
|
996
|
+
/>
|
|
997
|
+
);
|
|
998
|
+
}
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
### Stress Test Many Options
|
|
1002
|
+
|
|
1003
|
+
Test performance with many options on mobile.
|
|
1004
|
+
|
|
1005
|
+
```jsx
|
|
1006
|
+
function StressTestExample() {
|
|
1007
|
+
const { value, onChange } = useMultiSelect({
|
|
1008
|
+
initialValue: ['1', '5', '10'],
|
|
1009
|
+
});
|
|
1010
|
+
|
|
1011
|
+
const manyOptions = Array.from({ length: 100 }, (_, i) => ({
|
|
1012
|
+
value: (i + 1).toString(),
|
|
1013
|
+
label: `Option ${i + 1}`,
|
|
1014
|
+
description: i % 3 === 0 ? `Description for ${i + 1}` : undefined,
|
|
1015
|
+
disabled: i % 15 === 0,
|
|
1016
|
+
accessory: i % 10 === 0 ? <Icon color="fg" name="star" /> : undefined,
|
|
1017
|
+
}));
|
|
1018
|
+
|
|
1019
|
+
return (
|
|
1020
|
+
<Select
|
|
1021
|
+
type="multi"
|
|
1022
|
+
label="Stress Test - 100 Options"
|
|
1023
|
+
value={value}
|
|
1024
|
+
onChange={onChange}
|
|
1025
|
+
options={manyOptions}
|
|
1026
|
+
maxSelectedOptionsToShow={5}
|
|
1027
|
+
placeholder="Select from many"
|
|
1028
|
+
/>
|
|
1029
|
+
);
|
|
1030
|
+
}
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
### Custom styles
|
|
1034
|
+
|
|
1035
|
+
You can use custom styles on the various subcomponents in Select.
|
|
1036
|
+
|
|
1037
|
+
```jsx
|
|
1038
|
+
function CustomStylesExample() {
|
|
1039
|
+
const exampleOptions = [
|
|
1040
|
+
{ value: null, label: 'Remove selection' },
|
|
1041
|
+
{ value: '1', label: 'Option 1' },
|
|
1042
|
+
{ value: '2', label: 'Option 2' },
|
|
1043
|
+
{ value: '3', label: 'Option 3' },
|
|
1044
|
+
{ value: '4', label: 'Option 4' },
|
|
1045
|
+
];
|
|
1046
|
+
const [value, setValue] = useState('1');
|
|
1047
|
+
|
|
1048
|
+
return (
|
|
1049
|
+
<Select
|
|
1050
|
+
label="Single select - custom styles"
|
|
1051
|
+
onChange={setValue}
|
|
1052
|
+
options={exampleOptions}
|
|
1053
|
+
styles={{
|
|
1054
|
+
control: {
|
|
1055
|
+
backgroundColor: 'lightgray',
|
|
1056
|
+
padding: 10,
|
|
1057
|
+
},
|
|
1058
|
+
option: {
|
|
1059
|
+
backgroundColor: 'lightblue',
|
|
1060
|
+
},
|
|
1061
|
+
optionBlendStyles: {
|
|
1062
|
+
pressedBackground: 'darkgreen',
|
|
1063
|
+
},
|
|
1064
|
+
}}
|
|
1065
|
+
value={value}
|
|
1066
|
+
/>
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
```
|
|
1070
|
+
|
|
1071
|
+
### Custom class names
|
|
1072
|
+
|
|
1073
|
+
You can use custom class names on the various subcomponents in Select.
|
|
1074
|
+
|
|
1075
|
+
```jsx
|
|
1076
|
+
function CustomClassNamesExamples() {
|
|
1077
|
+
const exampleOptions = [
|
|
1078
|
+
{ value: null, label: 'Remove selection' },
|
|
1079
|
+
{ value: '1', label: 'Option 1' },
|
|
1080
|
+
{ value: '2', label: 'Option 2' },
|
|
1081
|
+
{ value: '3', label: 'Option 3' },
|
|
1082
|
+
{ value: '4', label: 'Option 4' },
|
|
1083
|
+
];
|
|
1084
|
+
const [value, setValue] = useState('1');
|
|
1085
|
+
|
|
1086
|
+
return (
|
|
1087
|
+
<Select
|
|
1088
|
+
classNames={{
|
|
1089
|
+
control: customControlStyles,
|
|
1090
|
+
option: customOptionStyles,
|
|
1091
|
+
}}
|
|
1092
|
+
label="Single select - class names"
|
|
1093
|
+
onChange={setValue}
|
|
1094
|
+
options={exampleOptions}
|
|
1095
|
+
placeholder="Empty value"
|
|
1096
|
+
value={value}
|
|
1097
|
+
/>
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
### Custom components
|
|
1103
|
+
|
|
1104
|
+
Select is highly customizable. Use the _Component_ props to customize the various subcomponents in Select.
|
|
1105
|
+
|
|
1106
|
+
#### Customizable subcomponents
|
|
1107
|
+
|
|
1108
|
+
- **SelectControlComponent**: Trigger component used to open and close the Select.
|
|
1109
|
+
- **SelectDropdownComponent**: Component which renders the dropdown menu and SelectOptionComponents.
|
|
1110
|
+
- **SelectOptionComponent**: Component which renders the content of an option in the select.
|
|
1111
|
+
- **SelectAllOptionComponent**: Component which renders the Select All option in a multi-select select menu.
|
|
1112
|
+
- **SelectEmptyDropdownContentsComponent**: Component which renders as the select menu's content when no options are passed in.
|
|
1113
|
+
|
|
1114
|
+
Below is a diagram to help visualize the Select anatomy.
|
|
1115
|
+
|
|
1116
|
+
```text
|
|
1117
|
+
Select
|
|
1118
|
+
├── SelectControlComponent (trigger to open/close)
|
|
1119
|
+
└── SelectDropdownComponent (dropdown menu)
|
|
1120
|
+
├── SelectAllOptionComponent
|
|
1121
|
+
├── SelectOptionComponent (option 1)
|
|
1122
|
+
├── SelectOptionComponent (option 2)
|
|
1123
|
+
├── SelectOptionComponent (option 3)
|
|
1124
|
+
└── SelectOptionComponent (option N...)
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
#### Example
|
|
1128
|
+
|
|
1129
|
+
```jsx
|
|
1130
|
+
function CustomComponentExamples() {
|
|
1131
|
+
const exampleOptions = [
|
|
1132
|
+
{ value: null, label: 'Remove selection' },
|
|
1133
|
+
{ value: '1', label: 'Option 1' },
|
|
1134
|
+
{ value: '2', label: 'Option 2' },
|
|
1135
|
+
{ value: '3', label: 'Option 3' },
|
|
1136
|
+
{ value: '4', label: 'Option 4' },
|
|
1137
|
+
];
|
|
1138
|
+
const [value, setValue] = useState('1');
|
|
1139
|
+
|
|
1140
|
+
const CustomControlComponent: SelectControlComponent = ({ value, setOpen }) => {
|
|
1141
|
+
return <Button onPress={() => setOpen(true)}>{value ?? 'Empty value'}</Button>;
|
|
1142
|
+
};
|
|
1143
|
+
|
|
1144
|
+
const CustomOptionComponent: SelectOptionComponent = ({ value, onPress }) => {
|
|
1145
|
+
return (
|
|
1146
|
+
<HStack justifyContent="center">
|
|
1147
|
+
<Spinner size={4} />
|
|
1148
|
+
<Button transparent onPress={() => onPress?.(value)} width="80%">
|
|
1149
|
+
<Text>{value ?? 'Empty value'}</Text>
|
|
1150
|
+
</Button>
|
|
1151
|
+
<Spinner size={4} />
|
|
1152
|
+
</HStack>
|
|
1153
|
+
);
|
|
1154
|
+
};
|
|
1155
|
+
|
|
1156
|
+
return (
|
|
1157
|
+
<Select
|
|
1158
|
+
SelectOptionComponent={CustomOptionComponent}
|
|
1159
|
+
label="Single select - custom option component"
|
|
1160
|
+
onChange={setValue}
|
|
1161
|
+
options={exampleOptions}
|
|
1162
|
+
placeholder="Empty value"
|
|
1163
|
+
value={value}
|
|
1164
|
+
/>
|
|
1165
|
+
);
|
|
1166
|
+
}
|
|
1167
|
+
```
|
|
1168
|
+
|
|
1169
|
+
## Props
|
|
1170
|
+
|
|
1171
|
+
| Prop | Type | Required | Default | Description |
|
|
1172
|
+
| --- | --- | --- | --- | --- |
|
|
1173
|
+
| `onChange` | `(value: Type extends multi ? SelectOptionValue \| SelectOptionValue[] \| null : SelectOptionValue \| null) => void` | Yes | `-` | - |
|
|
1174
|
+
| `options` | `(SelectOption<SelectOptionValue> & Pick<SelectOptionProps<Type, string>, media \| end \| accessory> & { Component?: SelectOptionComponent<Type, SelectOptionValue> \| undefined; })[]` | Yes | `-` | Array of options to display in the select dropdown |
|
|
1175
|
+
| `value` | `string \| SelectOptionValue[] \| null` | Yes | `-` | - |
|
|
1176
|
+
| `SelectAllOptionComponent` | `SelectOptionComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the Select All option |
|
|
1177
|
+
| `SelectControlComponent` | `SelectControlComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the select control |
|
|
1178
|
+
| `SelectDropdownComponent` | `SelectDropdownComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the dropdown container |
|
|
1179
|
+
| `SelectEmptyDropdownContentsComponent` | `SelectEmptyDropdownContentComponent` | No | `-` | Custom component to render when no options are available |
|
|
1180
|
+
| `SelectOptionComponent` | `SelectOptionComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render individual options |
|
|
1181
|
+
| `accessibilityRoles` | `{ option?: AccessibilityRole; } \| undefined` | No | `-` | Accessibility roles for dropdown elements |
|
|
1182
|
+
| `accessory` | `ReactElement<CellAccessoryProps, string \| JSXElementConstructor<any>>` | No | `-` | - |
|
|
1183
|
+
| `clearAllLabel` | `string` | No | `-` | Label for the Clear All option in multi-select mode |
|
|
1184
|
+
| `compact` | `boolean` | No | `-` | Whether to use compact styling for the select |
|
|
1185
|
+
| `defaultOpen` | `boolean` | No | `-` | Initial open state when component mounts (uncontrolled mode) |
|
|
1186
|
+
| `disableClickOutsideClose` | `boolean` | No | `-` | Whether clicking outside the dropdown should close it |
|
|
1187
|
+
| `disabled` | `boolean` | No | `false` | Toggles input interactability and opacity |
|
|
1188
|
+
| `emptyOptionsLabel` | `string` | No | `-` | Label displayed when there are no options available |
|
|
1189
|
+
| `end` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | End-aligned content (e.g., value, status). Replaces the deprecated detail prop. |
|
|
1190
|
+
| `endNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Adds content to the end of the inner input. Refer to diagram for location of endNode in InputStack component |
|
|
1191
|
+
| `helperText` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Helper text displayed below the select |
|
|
1192
|
+
| `hiddenSelectedOptionsLabel` | `string` | No | `-` | Label to show for showcasing count of hidden selected options |
|
|
1193
|
+
| `hideSelectAll` | `boolean` | No | `-` | Whether to hide the Select All option in multi-select mode |
|
|
1194
|
+
| `label` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Label displayed above the control |
|
|
1195
|
+
| `labelVariant` | `inside \| outside` | No | `'outside'` | The variant of the label. Only used when compact is not true. |
|
|
1196
|
+
| `maxSelectedOptionsToShow` | `number` | No | `-` | Maximum number of selected options to show before truncating |
|
|
1197
|
+
| `media` | `ReactElement` | No | `-` | Media rendered at the start of the cell (icon, avatar, image, etc). |
|
|
1198
|
+
| `open` | `boolean` | No | `-` | Controlled open state of the dropdown |
|
|
1199
|
+
| `placeholder` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Placeholder text displayed when no option is selected |
|
|
1200
|
+
| `ref` | `null \| (instance: SelectRef \| null) => void \| RefObject<SelectRef>` | No | `-` | - |
|
|
1201
|
+
| `removeSelectedOptionAccessibilityLabel` | `string` | No | `-` | Accessibility label for each chip in a multi-select |
|
|
1202
|
+
| `selectAllLabel` | `string` | No | `-` | Label for the Select All option in multi-select mode |
|
|
1203
|
+
| `setOpen` | `((open: boolean \| ((open: boolean) => boolean)) => void)` | No | `-` | Callback to update the open state |
|
|
1204
|
+
| `startNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Adds content to the start of the inner input. Refer to diagram for location of startNode in InputStack component |
|
|
1205
|
+
| `style` | `null \| false \| ViewStyle \| RegisteredStyle<ViewStyle> \| RecursiveArray<Falsy \| ViewStyle \| RegisteredStyle<ViewStyle>>` | No | `-` | Inline styles for the root element |
|
|
1206
|
+
| `styles` | `{ root?: StyleProp<ViewStyle>; control?: StyleProp<ViewStyle>; controlStartNode?: StyleProp<ViewStyle>; controlInputNode?: StyleProp<ViewStyle>; controlValueNode?: StyleProp<ViewStyle>; controlLabelNode?: StyleProp<ViewStyle>; controlHelperTextNode?: StyleProp<ViewStyle>; controlEndNode?: StyleProp<ViewStyle>; controlBlendStyles?: InteractableBlendStyles; dropdown?: StyleProp<ViewStyle>; option?: StyleProp<ViewStyle>; optionCell?: StyleProp<ViewStyle>; optionContent?: StyleProp<ViewStyle>; optionLabel?: StyleProp<ViewStyle>; optionDescription?: StyleProp<ViewStyle>; optionBlendStyles?: InteractableBlendStyles \| undefined; selectAllDivider?: StyleProp<ViewStyle>; emptyContentsContainer?: StyleProp<ViewStyle>; emptyContentsText?: StyleProp<ViewStyle>; } \| undefined` | No | `-` | Custom styles for different parts of the select |
|
|
1207
|
+
| `testID` | `string` | No | `-` | Test ID for the root element |
|
|
1208
|
+
| `type` | `single \| multi` | No | `-` | Whether the select allows single or multiple selections |
|
|
1209
|
+
| `variant` | `primary \| secondary \| positive \| negative \| foregroundMuted \| foreground` | No | `-` | Determines the sentiment of the input. Because we allow startContent and endContent to be custom ReactNode, the content placed inside these slots will not change colors according to the variant. You will have to add that yourself |
|
|
1210
|
+
|
|
1211
|
+
|