0
# Types and Interfaces
1
2
React-Select provides comprehensive TypeScript support with generic types, interfaces, and utility types that ensure type safety throughout the component system. All interfaces support generic Option and Group types for maximum flexibility.
3
4
## Capabilities
5
6
### Core Data Types
7
8
Fundamental type definitions for options, values, and data structures.
9
10
```typescript { .api }
11
/**
12
* Base interface for option groups containing multiple options
13
* @template Option - The option data type
14
*/
15
interface GroupBase<Option> {
16
/** Array of options within this group */
17
readonly options: readonly Option[];
18
/** Optional label for the group header */
19
readonly label?: string;
20
}
21
22
/**
23
* Union type for arrays containing options or groups
24
* @template Option - The option data type
25
* @template Group - The group data type extending GroupBase<Option>
26
*/
27
type OptionsOrGroups<Option, Group extends GroupBase<Option>> = readonly (Option | Group)[];
28
29
/**
30
* Simple array of options without grouping
31
* @template Option - The option data type
32
*/
33
type Options<Option> = readonly Option[];
34
35
/**
36
* Single value type - an option or null for no selection
37
* @template Option - The option data type
38
*/
39
type SingleValue<Option> = Option | null;
40
41
/**
42
* Multi-value type - readonly array of selected options
43
* @template Option - The option data type
44
*/
45
type MultiValue<Option> = readonly Option[];
46
47
/**
48
* Union type for any value prop - single or multi
49
* @template Option - The option data type
50
*/
51
type PropsValue<Option> = MultiValue<Option> | SingleValue<Option>;
52
53
/**
54
* Conditional type for onChange values based on isMulti flag
55
* @template Option - The option data type
56
* @template IsMulti - Boolean flag indicating multi-select mode
57
*/
58
type OnChangeValue<Option, IsMulti extends boolean> =
59
IsMulti extends true ? MultiValue<Option> : SingleValue<Option>;
60
```
61
62
**Usage Examples:**
63
64
```typescript
65
// Basic option type
66
interface ColorOption {
67
value: string;
68
label: string;
69
color: string;
70
}
71
72
// Grouped options
73
interface ColorGroup extends GroupBase<ColorOption> {
74
label: string;
75
options: readonly ColorOption[];
76
}
77
78
const colorGroups: OptionsOrGroups<ColorOption, ColorGroup> = [
79
{
80
label: "Primary Colors",
81
options: [
82
{ value: "red", label: "Red", color: "#ff0000" },
83
{ value: "blue", label: "Blue", color: "#0000ff" },
84
{ value: "yellow", label: "Yellow", color: "#ffff00" },
85
],
86
},
87
{
88
label: "Secondary Colors",
89
options: [
90
{ value: "green", label: "Green", color: "#00ff00" },
91
{ value: "orange", label: "Orange", color: "#ffa500" },
92
{ value: "purple", label: "Purple", color: "#800080" },
93
],
94
},
95
];
96
97
// Typed select usage
98
const TypedSelect = () => {
99
const [value, setValue] = useState<SingleValue<ColorOption>>(null);
100
101
return (
102
<Select<ColorOption, false, ColorGroup>
103
value={value}
104
onChange={setValue}
105
options={colorGroups}
106
/>
107
);
108
};
109
```
110
111
### Action and Meta Types
112
113
Types for handling change events and understanding what triggered them.
114
115
```typescript { .api }
116
/**
117
* Action metadata provided to onChange handlers
118
* @template Option - The option data type
119
*/
120
interface ActionMeta<Option> {
121
/** The action that triggered the change */
122
action:
123
| 'select-option' // Option was selected
124
| 'deselect-option' // Option was deselected (multi-select)
125
| 'remove-value' // Value was removed (multi-select)
126
| 'pop-value' // Last value was removed via backspace
127
| 'set-value' // Value was set programmatically
128
| 'clear' // All values were cleared
129
| 'create-option'; // New option was created (CreatableSelect)
130
131
/** Form field name if provided */
132
name?: string;
133
134
/** The option involved in the action (for select/deselect/create) */
135
option?: Option;
136
137
/** Single removed value (for remove-value action) */
138
removedValue?: Option;
139
140
/** Multiple removed values (for clear action) */
141
removedValues?: Option[];
142
}
143
144
/**
145
* Input change action metadata
146
*/
147
interface InputActionMeta {
148
/** The action that triggered the input change */
149
action:
150
| 'set-value' // Input value set programmatically
151
| 'input-change' // User typed in input
152
| 'input-blur' // Input lost focus
153
| 'menu-close'; // Menu was closed
154
155
/** Previous input value */
156
prevInputValue: string;
157
}
158
159
/**
160
* Focus direction for keyboard navigation
161
*/
162
type FocusDirection = 'up' | 'down' | 'pageup' | 'pagedown' | 'first' | 'last';
163
164
/**
165
* Menu placement options
166
*/
167
type MenuPlacement = 'auto' | 'bottom' | 'top';
168
169
/**
170
* Menu CSS position
171
*/
172
type MenuPosition = 'absolute' | 'fixed';
173
174
/**
175
* Set value action type for programmatic changes
176
*/
177
type SetValueAction = 'set-value';
178
```
179
180
**Usage Examples:**
181
182
```typescript
183
// Handling different action types
184
const handleChange = (
185
newValue: OnChangeValue<Option, false>,
186
actionMeta: ActionMeta<Option>
187
) => {
188
console.log(`Action: ${actionMeta.action}`);
189
190
switch (actionMeta.action) {
191
case 'select-option':
192
console.log('Selected:', actionMeta.option);
193
break;
194
case 'clear':
195
console.log('Cleared all values:', actionMeta.removedValues);
196
break;
197
case 'remove-value':
198
console.log('Removed:', actionMeta.removedValue);
199
break;
200
case 'create-option':
201
console.log('Created new option:', actionMeta.option);
202
// Save to database or update options list
203
break;
204
}
205
206
setValue(newValue);
207
};
208
209
// Input change handling
210
const handleInputChange = (
211
inputValue: string,
212
actionMeta: InputActionMeta
213
) => {
214
if (actionMeta.action === 'input-change') {
215
// Handle user typing
216
setInputValue(inputValue);
217
}
218
};
219
```
220
221
### Component Props Types
222
223
Complete type definitions for all component props interfaces.
224
225
```typescript { .api }
226
/**
227
* Props for the main Control component
228
* @template Option - The option data type
229
* @template IsMulti - Boolean flag for multi-select
230
* @template Group - The group data type
231
*/
232
interface ControlProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>>
233
extends CommonPropsAndClassName<Option, IsMulti, Group> {
234
/** Whether the control is focused */
235
isFocused: boolean;
236
/** Whether the control is disabled */
237
isDisabled: boolean;
238
/** Child elements (ValueContainer, IndicatorsContainer) */
239
children: ReactNode;
240
/** Additional inner props passed to the control element */
241
innerProps: JSX.IntrinsicElements['div'];
242
}
243
244
/**
245
* Props for individual Option components
246
* @template Option - The option data type
247
* @template IsMulti - Boolean flag for multi-select
248
* @template Group - The group data type
249
*/
250
interface OptionProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>>
251
extends CommonPropsAndClassName<Option, IsMulti, Group> {
252
/** The option data */
253
data: Option;
254
/** Whether this option is disabled */
255
isDisabled: boolean;
256
/** Whether this option is focused */
257
isFocused: boolean;
258
/** Whether this option is selected */
259
isSelected: boolean;
260
/** Child content (usually the option label) */
261
children: ReactNode;
262
/** Additional inner props passed to the option element */
263
innerProps: JSX.IntrinsicElements['div'];
264
}
265
266
/**
267
* Props for Menu component
268
* @template Option - The option data type
269
* @template IsMulti - Boolean flag for multi-select
270
* @template Group - The group data type
271
*/
272
interface MenuProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>>
273
extends CommonPropsAndClassName<Option, IsMulti, Group> {
274
/** Child elements (MenuList) */
275
children: ReactNode;
276
/** Additional inner props passed to the menu element */
277
innerProps: JSX.IntrinsicElements['div'];
278
/** Menu placement */
279
placement: MenuPlacement;
280
}
281
282
/**
283
* Props for MultiValue components
284
* @template Option - The option data type
285
* @template IsMulti - Boolean flag for multi-select
286
* @template Group - The group data type
287
*/
288
interface MultiValueProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>>
289
extends CommonPropsAndClassName<Option, IsMulti, Group> {
290
/** The option data for this multi-value */
291
data: Option;
292
/** Child elements (MultiValueContainer) */
293
children: ReactNode;
294
/** Index of this value in the values array */
295
index: number;
296
/** Whether this multi-value is disabled */
297
isDisabled: boolean;
298
/** Function to remove this value */
299
removeProps: {
300
onClick: MouseEventHandler<HTMLDivElement>;
301
onTouchEnd: TouchEventHandler<HTMLDivElement>;
302
onMouseDown: MouseEventHandler<HTMLDivElement>;
303
};
304
}
305
306
/**
307
* Props for SingleValue component
308
* @template Option - The option data type
309
* @template IsMulti - Boolean flag for multi-select
310
* @template Group - The group data type
311
*/
312
interface SingleValueProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>>
313
extends CommonPropsAndClassName<Option, IsMulti, Group> {
314
/** The selected option data */
315
data: Option;
316
/** Whether the value is disabled */
317
isDisabled: boolean;
318
/** Child content (usually the option label) */
319
children: ReactNode;
320
}
321
322
/**
323
* Props for Input component
324
* @template Option - The option data type
325
* @template IsMulti - Boolean flag for multi-select
326
* @template Group - The group data type
327
*/
328
interface InputProps<Option, IsMulti extends boolean, Group extends GroupBase<Option>>
329
extends CommonPropsAndClassName<Option, IsMulti, Group> {
330
/** Current input value */
331
value: string;
332
/** Auto-complete attribute */
333
autoComplete: string;
334
/** Input ID */
335
id: string;
336
/** Whether the input is disabled */
337
isDisabled: boolean;
338
/** Whether the input is hidden */
339
isHidden: boolean;
340
/** Additional props passed to the input element */
341
innerProps?: JSX.IntrinsicElements['input'];
342
}
343
```
344
345
### Accessibility Types
346
347
Types for ARIA support and accessibility features.
348
349
```typescript { .api }
350
/**
351
* Configuration for ARIA live region messages
352
* @template Option - The option data type
353
* @template IsMulti - Boolean flag for multi-select
354
* @template Group - The group data type
355
*/
356
interface AriaLiveMessages<Option, IsMulti extends boolean, Group extends GroupBase<Option>> {
357
/** Message when guidance should be provided */
358
guidance?: (props: AriaGuidanceProps) => string;
359
/** Message when selection changes */
360
onChange?: (props: AriaOnChangeProps<Option, IsMulti>) => string;
361
/** Message when options are filtered */
362
onFilter?: (props: AriaOnFilterProps<Option>) => string;
363
/** Message when focus changes */
364
onFocus?: (props: AriaOnFocusProps<Option>) => string;
365
}
366
367
/**
368
* Props for guidance messages
369
*/
370
interface AriaGuidanceProps {
371
/** Whether the component is searchable */
372
isSearchable: boolean;
373
/** Whether multiple selection is enabled */
374
isMulti: boolean;
375
/** Current selection count */
376
selectionCount: number;
377
/** Tab index value */
378
tabSelectsValue: boolean;
379
}
380
381
/**
382
* Props for change announcement messages
383
* @template Option - The option data type
384
* @template IsMulti - Boolean flag for multi-select
385
*/
386
interface AriaOnChangeProps<Option, IsMulti extends boolean> {
387
/** The action that occurred */
388
action: ActionMeta<Option>['action'];
389
/** Label of affected option */
390
label?: string;
391
/** Labels of all affected options */
392
labels?: string[];
393
/** Current value after change */
394
value: string;
395
}
396
397
/**
398
* Props for focus announcement messages
399
* @template Option - The option data type
400
*/
401
interface AriaOnFocusProps<Option> {
402
/** Currently focused option */
403
focused: Option;
404
/** Label of focused option */
405
label: string;
406
/** Whether the option is selected */
407
isSelected: boolean;
408
/** Whether the option is disabled */
409
isDisabled: boolean;
410
}
411
412
/**
413
* Props for filter announcement messages
414
* @template Option - The option data type
415
*/
416
interface AriaOnFilterProps<Option> {
417
/** Current input value */
418
inputValue: string;
419
/** Array of filtered results */
420
resultsMessage: string;
421
}
422
```
423
424
### Utility Types
425
426
Helper types for advanced use cases and type manipulation.
427
428
```typescript { .api }
429
/**
430
* Extract the Option type from a Select component type
431
*/
432
type OptionTypeBase = {
433
label: ReactNode;
434
value: string | number;
435
isDisabled?: boolean;
436
};
437
438
/**
439
* Common props shared across all components
440
* @template Option - The option data type
441
* @template IsMulti - Boolean flag for multi-select
442
* @template Group - The group data type
443
*/
444
interface CommonPropsAndClassName<Option, IsMulti extends boolean, Group extends GroupBase<Option>> {
445
/** Additional CSS class name */
446
className?: string;
447
/** CSS class name prefix for BEM-style naming */
448
classNamePrefix?: string;
449
/** Component configuration */
450
selectProps: Props<Option, IsMulti, Group>;
451
}
452
453
/**
454
* Function type for getting option labels
455
* @template Option - The option data type
456
*/
457
type GetOptionLabel<Option> = (option: Option) => string;
458
459
/**
460
* Function type for getting option values
461
* @template Option - The option data type
462
*/
463
type GetOptionValue<Option> = (option: Option) => string;
464
465
/**
466
* Function type for checking if option is disabled
467
* @template Option - The option data type
468
*/
469
type IsOptionDisabled<Option> = (option: Option, selectValue: Options<Option>) => boolean;
470
471
/**
472
* Filter option with additional metadata
473
* @template Option - The option data type
474
*/
475
interface FilterOptionOption<Option> {
476
label: string;
477
value: string;
478
data: Option;
479
}
480
481
/**
482
* Function type for custom filtering
483
* @template Option - The option data type
484
*/
485
type FilterOptionFunction<Option> = (
486
option: FilterOptionOption<Option>,
487
inputValue: string
488
) => boolean;
489
```
490
491
**Usage Examples:**
492
493
```typescript
494
// Custom option type with additional metadata
495
interface UserOption extends OptionTypeBase {
496
value: string;
497
label: string;
498
email: string;
499
avatar: string;
500
role: 'admin' | 'user' | 'guest';
501
isDisabled?: boolean;
502
}
503
504
// Utility functions with proper typing
505
const getUserLabel: GetOptionLabel<UserOption> = (user) => user.label;
506
const getUserValue: GetOptionValue<UserOption> = (user) => user.value;
507
const isUserDisabled: IsOptionDisabled<UserOption> = (user) => user.role === 'guest';
508
509
// Custom component with proper typing
510
const UserOption: React.FC<OptionProps<UserOption, false, GroupBase<UserOption>>> = ({
511
data,
512
children,
513
isSelected,
514
isFocused,
515
...props
516
}) => (
517
<components.Option {...props} data={data} isSelected={isSelected} isFocused={isFocused}>
518
<div className="user-option">
519
<img src={data.avatar} alt="" className="avatar" />
520
<div>
521
<div className="name">{children}</div>
522
<div className="email">{data.email}</div>
523
<div className="role">{data.role}</div>
524
</div>
525
</div>
526
</components.Option>
527
);
528
529
// Typed select with custom option
530
const UserSelect = () => (
531
<Select<UserOption, false, GroupBase<UserOption>>
532
options={users}
533
getOptionLabel={getUserLabel}
534
getOptionValue={getUserValue}
535
isOptionDisabled={isUserDisabled}
536
components={{ Option: UserOption }}
537
/>
538
);
539
```
540
541
### Advanced Generic Types
542
543
Complex type utilities for advanced customization scenarios.
544
545
```typescript { .api }
546
/**
547
* Extract component props type from SelectComponentsConfig
548
* @template K - The component key
549
* @template Option - The option data type
550
* @template IsMulti - Boolean flag for multi-select
551
* @template Group - The group data type
552
*/
553
type ComponentProps<
554
K extends keyof SelectComponentsConfig<any, any, any>,
555
Option,
556
IsMulti extends boolean,
557
Group extends GroupBase<Option>
558
> = SelectComponentsConfig<Option, IsMulti, Group>[K] extends ComponentType<infer P> ? P : never;
559
560
/**
561
* Utility type for creating themed style functions
562
* @template T - The component props type
563
*/
564
type ThemedStyleFunction<T> = (base: CSSObject, state: T, theme: Theme) => CSSObject;
565
566
/**
567
* Helper type for creating strongly-typed component factories
568
* @template Option - The option data type
569
* @template IsMulti - Boolean flag for multi-select
570
* @template Group - The group data type
571
*/
572
type SelectComponentFactory<Option, IsMulti extends boolean, Group extends GroupBase<Option>> = {
573
[K in keyof SelectComponentsConfig<Option, IsMulti, Group>]: ComponentType<
574
ComponentProps<K, Option, IsMulti, Group>
575
>;
576
};
577
578
/**
579
* Utility type for partial component configurations
580
* @template Option - The option data type
581
* @template IsMulti - Boolean flag for multi-select
582
* @template Group - The group data type
583
*/
584
type PartialSelectComponents<Option, IsMulti extends boolean, Group extends GroupBase<Option>> =
585
Partial<SelectComponentsConfig<Option, IsMulti, Group>>;
586
```
587
588
**Usage Examples:**
589
590
```typescript
591
// Strongly-typed component factory
592
const createComponents = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>():
593
SelectComponentFactory<Option, IsMulti, Group> => ({
594
Option: (props: ComponentProps<'Option', Option, IsMulti, Group>) => (
595
<div {...props.innerProps}>
596
{props.children}
597
</div>
598
),
599
Control: (props: ComponentProps<'Control', Option, IsMulti, Group>) => (
600
<div {...props.innerProps}>
601
{props.children}
602
</div>
603
),
604
// ... other components
605
});
606
607
// Themed style utilities
608
const createThemedStyles = <Option, IsMulti extends boolean, Group extends GroupBase<Option>>() => ({
609
control: ((base, state, theme) => ({
610
...base,
611
borderColor: state.isFocused ? theme.colors.primary : theme.colors.neutral20,
612
boxShadow: state.isFocused ? `0 0 0 1px ${theme.colors.primary}` : 'none',
613
})) as ThemedStyleFunction<ControlProps<Option, IsMulti, Group>>,
614
615
option: ((base, state, theme) => ({
616
...base,
617
backgroundColor: state.isSelected
618
? theme.colors.primary
619
: state.isFocused
620
? theme.colors.primary25
621
: 'transparent',
622
color: state.isSelected ? 'white' : theme.colors.neutral80,
623
})) as ThemedStyleFunction<OptionProps<Option, IsMulti, Group>>,
624
});
625
```