-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat: Add support for multiple selection to Select and Picker #8734
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
/** The textValue of the currently selected item. */ | ||
selectedText: string | null | ||
/** The object values of the currently selected items. */ | ||
selectedItems: (T | null)[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want this to include null? The other option would be to filter out items that didn't set a value
on the ListBoxItem
. But then we'd need some other way of knowing the total selected item count at least.
Build successful! 🎉 |
Build successful! 🎉 |
Build successful! 🎉 |
## API Changes
react-aria-components/react-aria-components:Select-Select <T extends {} = {
+Select <M extends SelectionMode = 'single', T extends {} = {
}> {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children?: ChildrenOrFunction<SelectRenderProps>
className?: ClassNameOrFunction<SelectRenderProps>
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
disabledKeys?: Iterable<Key>
excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
name?: string
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string = 'Select an item' (localized)
- selectedKey?: Key | null
+ selectionMode?: SelectionMode = 'single'
slot?: string | null
style?: StyleOrFunction<SelectRenderProps>
- validate?: (Key) => ValidationError | boolean | null | undefined
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
+ value?: ValueType<SelectionMode>
} /react-aria-components:SelectProps-SelectProps <T extends {} = {
+SelectProps <M extends SelectionMode = 'single', T extends {} = {
}> {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children?: ChildrenOrFunction<SelectRenderProps>
className?: ClassNameOrFunction<SelectRenderProps>
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
disabledKeys?: Iterable<Key>
excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
name?: string
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string = 'Select an item' (localized)
- selectedKey?: Key | null
+ selectionMode?: SelectionMode = 'single'
slot?: string | null
style?: StyleOrFunction<SelectRenderProps>
- validate?: (Key) => ValidationError | boolean | null | undefined
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
+ value?: ValueType<SelectionMode>
} /react-aria-components:SelectValueRenderProps SelectValueRenderProps <T> {
isPlaceholder: boolean
- selectedItem: T | null
- selectedText: string | null
+ selectedItems: Array<T | null>
+ selectedText: string
+ state: SelectState<T, 'single' | 'multiple'>
} /react-aria-components:SelectState-SelectState <T> {
+SelectState <M extends SelectionMode = 'single', T> {
close: () => void
collection: Collection<Node<T>>
commitValidation: () => void
- defaultSelectedKey: Key | null
+ defaultValue: ValueType<SelectionMode>
disabledKeys: Set<Key>
displayValidation: ValidationResult
focusStrategy: FocusStrategy | null
isFocused: boolean
isOpen: boolean
open: (FocusStrategy | null) => void
realtimeValidation: ValidationResult
resetValidation: () => void
- selectedItem: Node<T> | null
- selectedKey: Key | null
+ selectedItems: Array<Node<T>>
selectionManager: SelectionManager
setFocused: (boolean) => void
setOpen: (boolean) => void
- setSelectedKey: (Key | null) => void
+ setValue: (Key | Array<Key> | null) => void
toggle: (FocusStrategy | null) => void
updateValidation: (ValidationResult) => void
+ value: ValueType<SelectionMode>
} @react-aria/select/@react-aria/select:useSelect-useSelect <T> {
+useSelect <M extends SelectionMode = 'single', T> {
- props: AriaSelectOptions<T>
- state: SelectState<T>
+ props: AriaSelectOptions<T, M>
+ state: SelectState<T, M>
ref: RefObject<HTMLElement | null>
returnVal: undefined
} /@react-aria/select:useHiddenSelect-useHiddenSelect <T> {
+useHiddenSelect <M extends SelectionMode = 'single', T> {
props: AriaHiddenSelectOptions
- state: SelectState<T>
+ state: SelectState<T, M>
triggerRef: RefObject<FocusableElement | null>
returnVal: undefined
} /@react-aria/select:HiddenSelect-HiddenSelect <T> {
+HiddenSelect <M extends SelectionMode = 'single', T> {
autoComplete?: string
form?: string
isDisabled?: boolean
label?: ReactNode
name?: string
- state: SelectState<T>
+ state: SelectState<T, SelectionMode>
triggerRef: RefObject<FocusableElement | null>
} /@react-aria/select:AriaSelectOptions-AriaSelectOptions <T> {
+AriaSelectOptions <M extends SelectionMode = 'single', T> {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
items?: Iterable<T>
keyboardDelegate?: KeyboardDelegate
label?: ReactNode
name?: string
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string
- selectedKey?: Key | null
- validate?: (Key) => ValidationError | boolean | null | undefined
+ selectionMode?: SelectionMode = 'single'
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
+ value?: ValueType<SelectionMode>
} /@react-aria/select:SelectAria-SelectAria <T> {
+SelectAria <M extends SelectionMode = 'single', T> {
descriptionProps: DOMAttributes
errorMessageProps: DOMAttributes
- hiddenSelectProps: HiddenSelectProps<T>
+ hiddenSelectProps: HiddenSelectProps<T, SelectionMode>
isInvalid: boolean
labelProps: DOMAttributes
menuProps: AriaListBoxOptions<T>
triggerProps: AriaButtonProps
validationErrors: Array<string>
valueProps: DOMAttributes
} /@react-aria/select:HiddenSelectProps-HiddenSelectProps <T> {
+HiddenSelectProps <M extends SelectionMode = 'single', T> {
autoComplete?: string
form?: string
isDisabled?: boolean
label?: ReactNode
name?: string
- state: SelectState<T>
+ state: SelectState<T, SelectionMode>
triggerRef: RefObject<FocusableElement | null>
} /@react-aria/select:AriaSelectProps-AriaSelectProps <T> {
+AriaSelectProps <M extends SelectionMode = 'single', T> {
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children: CollectionChildren<T>
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
name?: string
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string
- selectedKey?: Key | null
- validate?: (Key) => ValidationError | boolean | null | undefined
+ selectionMode?: SelectionMode = 'single'
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
+ value?: ValueType<SelectionMode>
} @react-spectrum/picker/@react-spectrum/picker:Picker Picker <T extends {}> {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
align?: Alignment = 'start'
alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
bottom?: Responsive<DimensionValue>
children: CollectionChildren<{}>
contextualHelp?: ReactNode
defaultOpen?: boolean
defaultSelectedKey?: Key
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
end?: Responsive<DimensionValue>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
excludeFromTabOrder?: boolean
flex?: Responsive<string | number | boolean>
flexBasis?: Responsive<number | string>
flexGrow?: Responsive<number>
flexShrink?: Responsive<number>
form?: string
gridArea?: Responsive<string>
gridColumn?: Responsive<string>
gridColumnEnd?: Responsive<string>
gridColumnStart?: Responsive<string>
gridRow?: Responsive<string>
gridRowEnd?: Responsive<string>
gridRowStart?: Responsive<string>
height?: Responsive<DimensionValue>
id?: string
isDisabled?: boolean
isHidden?: Responsive<boolean>
isInvalid?: boolean
isLoading?: boolean
isOpen?: boolean
isQuiet?: boolean
isRequired?: boolean
items?: Iterable<{}>
justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
left?: Responsive<DimensionValue>
margin?: Responsive<DimensionValue>
marginBottom?: Responsive<DimensionValue>
marginEnd?: Responsive<DimensionValue>
marginStart?: Responsive<DimensionValue>
marginTop?: Responsive<DimensionValue>
marginX?: Responsive<DimensionValue>
marginY?: Responsive<DimensionValue>
maxHeight?: Responsive<DimensionValue>
maxWidth?: Responsive<DimensionValue>
menuWidth?: DimensionValue
minHeight?: Responsive<DimensionValue>
minWidth?: Responsive<DimensionValue>
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
onSelectionChange?: (Key | null) => void
order?: Responsive<number>
placeholder?: string
position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
right?: Responsive<DimensionValue>
selectedKey?: Key | null
shouldFlip?: boolean = true
start?: Responsive<DimensionValue>
top?: Responsive<DimensionValue>
- validate?: (Key) => ValidationError | boolean | null | undefined
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
width?: Responsive<DimensionValue>
zIndex?: Responsive<number>
} /@react-spectrum/picker:SpectrumPickerProps SpectrumPickerProps <T> {
UNSAFE_className?: string
UNSAFE_style?: CSSProperties
align?: Alignment = 'start'
alignSelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'center' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'stretch'>
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
bottom?: Responsive<DimensionValue>
children: CollectionChildren<T>
contextualHelp?: ReactNode
defaultOpen?: boolean
defaultSelectedKey?: Key
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
end?: Responsive<DimensionValue>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
excludeFromTabOrder?: boolean
flex?: Responsive<string | number | boolean>
flexBasis?: Responsive<number | string>
flexGrow?: Responsive<number>
flexShrink?: Responsive<number>
form?: string
gridArea?: Responsive<string>
gridColumn?: Responsive<string>
gridColumnEnd?: Responsive<string>
gridColumnStart?: Responsive<string>
gridRow?: Responsive<string>
gridRowEnd?: Responsive<string>
gridRowStart?: Responsive<string>
height?: Responsive<DimensionValue>
id?: string
isDisabled?: boolean
isHidden?: Responsive<boolean>
isInvalid?: boolean
isLoading?: boolean
isOpen?: boolean
isQuiet?: boolean
isRequired?: boolean
items?: Iterable<T>
justifySelf?: Responsive<'auto' | 'normal' | 'start' | 'end' | 'flex-start' | 'flex-end' | 'self-start' | 'self-end' | 'center' | 'left' | 'right' | 'stretch'>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
left?: Responsive<DimensionValue>
margin?: Responsive<DimensionValue>
marginBottom?: Responsive<DimensionValue>
marginEnd?: Responsive<DimensionValue>
marginStart?: Responsive<DimensionValue>
marginTop?: Responsive<DimensionValue>
marginX?: Responsive<DimensionValue>
marginY?: Responsive<DimensionValue>
maxHeight?: Responsive<DimensionValue>
maxWidth?: Responsive<DimensionValue>
menuWidth?: DimensionValue
minHeight?: Responsive<DimensionValue>
minWidth?: Responsive<DimensionValue>
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
onSelectionChange?: (Key | null) => void
order?: Responsive<number>
placeholder?: string
position?: Responsive<'static' | 'relative' | 'absolute' | 'fixed' | 'sticky'>
right?: Responsive<DimensionValue>
selectedKey?: Key | null
shouldFlip?: boolean = true
start?: Responsive<DimensionValue>
top?: Responsive<DimensionValue>
- validate?: (Key) => ValidationError | boolean | null | undefined
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
width?: Responsive<DimensionValue>
zIndex?: Responsive<number>
} @react-spectrum/s2/@react-spectrum/s2:Picker-Picker <T extends {}> {
+Picker <M extends SelectionMode = 'single', T extends {}> {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
align?: 'start' | 'end' = 'start'
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children: ReactNode | ({}) => ReactNode
contextualHelp?: ReactNode
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
dependencies?: ReadonlyArray<any>
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
loadingState?: LoadingState
menuWidth?: number
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string = 'Select an item' (localized)
- selectedKey?: Key | null
+ selectionMode?: SelectionMode = 'single'
shouldFlip?: boolean = true
size?: 'S' | 'M' | 'L' | 'XL' = 'M'
slot?: string | null
styles?: StylesProp
- validate?: (Key) => ValidationError | boolean | null | undefined
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
+ value?: ValueType<SelectionMode>
} /@react-spectrum/s2:PickerProps-PickerProps <T extends {}> {
+PickerProps <M extends SelectionMode = 'single', T extends {}> {
UNSAFE_className?: UnsafeClassName
UNSAFE_style?: CSSProperties
align?: 'start' | 'end' = 'start'
aria-describedby?: string
aria-details?: string
aria-label?: string
aria-labelledby?: string
autoComplete?: string
autoFocus?: boolean
children: ReactNode | ({}) => ReactNode
contextualHelp?: ReactNode
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
dependencies?: ReadonlyArray<any>
description?: ReactNode
direction?: 'bottom' | 'top' = 'bottom'
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
excludeFromTabOrder?: boolean
form?: string
id?: string
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
labelAlign?: Alignment = 'start'
labelPosition?: LabelPosition = 'top'
loadingState?: LoadingState
menuWidth?: number
name?: string
necessityIndicator?: NecessityIndicator = 'icon'
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onLoadMore?: () => any
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string = 'Select an item' (localized)
- selectedKey?: Key | null
+ selectionMode?: SelectionMode = 'single'
shouldFlip?: boolean = true
size?: 'S' | 'M' | 'L' | 'XL' = 'M'
slot?: string | null
styles?: StylesProp
- validate?: (Key) => ValidationError | boolean | null | undefined
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'native' | 'aria' = 'native'
+ value?: ValueType<SelectionMode>
} @react-stately/select/@react-stately/select:useSelectState-useSelectState <T extends {}> {
+useSelectState <M extends SelectionMode = 'single', T extends {}> {
- props: SelectStateOptions<T>
+ props: SelectStateOptions<T, M>
returnVal: undefined
} /@react-stately/select:SelectProps-SelectProps <T> {
+SelectProps <M extends SelectionMode = 'single', T> {
autoFocus?: boolean
children: CollectionChildren<T>
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string
- selectedKey?: Key | null
- validate?: (Key) => ValidationError | boolean | null | undefined
+ selectionMode?: SelectionMode = 'single'
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
+ value?: ValueType<SelectionMode>
} /@react-stately/select:SelectState-SelectState <T> {
+SelectState <M extends SelectionMode = 'single', T> {
close: () => void
collection: Collection<Node<T>>
commitValidation: () => void
- defaultSelectedKey: Key | null
+ defaultValue: ValueType<SelectionMode>
disabledKeys: Set<Key>
displayValidation: ValidationResult
focusStrategy: FocusStrategy | null
isFocused: boolean
isOpen: boolean
open: (FocusStrategy | null) => void
realtimeValidation: ValidationResult
resetValidation: () => void
- selectedItem: Node<T> | null
- selectedKey: Key | null
+ selectedItems: Array<Node<T>>
selectionManager: SelectionManager
setFocused: (boolean) => void
setOpen: (boolean) => void
- setSelectedKey: (Key | null) => void
+ setValue: (Key | Array<Key> | null) => void
toggle: (FocusStrategy | null) => void
updateValidation: (ValidationResult) => void
+ value: ValueType<SelectionMode>
} /@react-stately/select:SelectStateOptions-SelectStateOptions <T> {
+SelectStateOptions <M extends SelectionMode = 'single', T> {
autoFocus?: boolean
collection?: Collection<Node<T>>
defaultOpen?: boolean
- defaultSelectedKey?: Key
+ defaultValue?: ValueType<SelectionMode>
description?: ReactNode
disabledKeys?: Iterable<Key>
errorMessage?: ReactNode | (ValidationResult) => ReactNode
isDisabled?: boolean
isInvalid?: boolean
isOpen?: boolean
isRequired?: boolean
items?: Iterable<T>
label?: ReactNode
onBlur?: (FocusEvent<Target>) => void
+ onChange?: (T) => void
onFocus?: (FocusEvent<Target>) => void
onFocusChange?: (boolean) => void
onKeyDown?: (KeyboardEvent) => void
onKeyUp?: (KeyboardEvent) => void
onOpenChange?: (boolean) => void
- onSelectionChange?: (Key | null) => void
placeholder?: string
- selectedKey?: Key | null
- validate?: (Key) => ValidationError | boolean | null | undefined
+ selectionMode?: SelectionMode = 'single'
+ validate?: (ValidationType<SelectionMode>) => ValidationError | boolean | null | undefined
validationBehavior?: 'aria' | 'native' = 'aria'
+ value?: ValueType<SelectionMode>
} |
if (e.target.multiple) { | ||
setValue(Array.from( | ||
e.target.selectedOptions, | ||
(option) => option.value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think currently we allow for Key
which is string | number
but this would change it to string
only right?
if (selectionMode === 'single') { | ||
let key = keys.values().next().value ?? null; | ||
setValue(key); | ||
triggerState.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
combine work to keep open with #8733 ?
Closes #8738
This adds support for selecting multiple items to RAC Select and S2 Picker. By default, the selected items are concatenated into a comma separated list. Using RAC SelectValue's render props, you can customize this to whatever string you want (e.g. "2 selected items"). Behavior is TBD for Spectrum.
The API is changing from using
selectedKey
to usingvalue
. When multi-select is enabled,value
accepts an array instead of a single id. This matches the native React DOM<select>
API. The old API is supported for backward compatibility, but only applies to single selection.Behaviorally, it uses the existing ListBox component which already supports multi-select. Typeahead and arrow key on the button while the select is closed is disabled when using multi-select, and the popover stays open after selection to facilitate selecting multiple items.