Selection
Many collection components support selecting items by clicking or tapping them, or by using the keyboard. This page discusses how to handle selection events, how to control selection programmatically, and the data structures used to represent a selection.
Multiple selection#
Selection is handled by the onSelectionChange
event, which is supported on most collection components. Controlled
behavior is supported by the selectedKeys
prop, and uncontrolled behavior is supported by the defaultSelectedKeys
prop. These props are passed to the top-level collection component, and accept a set of unique item keys that are selected.
This allows marking items as selected by their key even before they are loaded, which can be useful when you know
what items should be selected on initial render, before data loading has completed.
Selection is represented by a Set
object. You can also pass any iterable collection (e.g. an array) to the selectedKeys
and defaultSelectedKeys
props,
but the onSelectionChange
event will always pass back a Set.
Selection is supported on both static and dynamic collections. The following example shows how to implement controlled selection behavior on a static collection, but could be applied to a dynamic collection the same way.
let [selectedKeys setSelectedKeys] = useState(new Set());
<ListBox selectedKeys= selectedKeys onSelectionChange= setSelectedKeys>
<Item key="one">One</Item>
<Item key="two">Two</Item>
<Item key="three">Three</Item>
</ListBox>
let [selectedKeys setSelectedKeys] = useState(new Set());
<ListBox
selectedKeys= selectedKeys
onSelectionChange= setSelectedKeys>
<Item key="one">One</Item>
<Item key="two">Two</Item>
<Item key="three">Three</Item>
</ListBox>
let [
selectedKeys
setSelectedKeys
] = useState(new Set());
<ListBox
selectedKeys=
selectedKeys
onSelectionChange=
setSelectedKeys
>
<Item key="one">
One
</Item>
<Item key="two">
Two
</Item>
<Item key="three">
Three
</Item>
</ListBox>
Single selection#
So far, we've discussed multiple selection. However, you may wish to limit selection to a single item instead.
In some components, like a select or combo box, only single selection is supported. In this case, the singular
selectedKey
and defaultSelectedKey
props are available instead of their plural variants. These accept a
single key instead of a Set as their value, and onSelectionChange
is also called with a single key.
let [selectedKey setSelectedKey] = useState(null);
<ComboBox selectedKey= selectedKey onSelectionChange= setSelectedKey>
<Item key="one">One</Item>
<Item key="two">Two</Item>
<Item key="three">Three</Item>
</ComboBox>
let [selectedKey setSelectedKey] = useState(null);
<ComboBox
selectedKey= selectedKey
onSelectionChange= setSelectedKey>
<Item key="one">One</Item>
<Item key="two">Two</Item>
<Item key="three">Three</Item>
</ComboBox>
let [
selectedKey
setSelectedKey
] = useState(null);
<ComboBox
selectedKey=
selectedKey
onSelectionChange=
setSelectedKey
>
<Item key="one">
One
</Item>
<Item key="two">
Two
</Item>
<Item key="three">
Three
</Item>
</ComboBox>
In components which support multiple selection, you can limit the selection to a single item using the
selectionMode
prop. This continues to accept selectedKeys
and defaultSelectedKeys
as a Set, but it will
only contain a single key at a time.
let [selectedKeys setSelectedKeys] = useState(new Set());
<ListBox
selectionMode="single"
selectedKeys= selectedKeys
onSelectionChange= setSelectedKeys>
<Item key="one">One</Item>
<Item key="two">Two</Item>
<Item key="three">Three</Item>
</ListBox>
let [selectedKeys setSelectedKeys] = useState(new Set());
<ListBox
selectionMode="single"
selectedKeys= selectedKeys
onSelectionChange= setSelectedKeys>
<Item key="one">One</Item>
<Item key="two">Two</Item>
<Item key="three">Three</Item>
</ListBox>
let [
selectedKeys
setSelectedKeys
] = useState(new Set());
<ListBox
selectionMode="single"
selectedKeys=
selectedKeys
onSelectionChange=
setSelectedKeys
>
<Item key="one">
One
</Item>
<Item key="two">
Two
</Item>
<Item key="three">
Three
</Item>
</ListBox>
Dynamic data#
When data in a collection changes, the selection state may need to be updated accordingly. For example, if a selected item is
deleted, it should be removed from the set of selected keys. You can do this yourself, but the
and
hooks can handle this automatically.
let list = useListData({
initialItems: [{name: 'Aardvark'} {name: 'Kangaroo'} {name: 'Snake'}]
initialSelectedKeys: ['Kangaroo']
getKey: (item) => itemname
});
function removeItem() {
// Removing the list item will also remove it from the selection state.
listremove('Kangaroo');
}
<ListBox
items= listitems
selectedKeys= listselectedKeys
onSelectionChange= listsetSelectedKeys>
(item) => <Item key= itemname> itemname</Item>
</ListBox>
let list = useListData({
initialItems: [
{name: 'Aardvark'}
{name: 'Kangaroo'}
{name: 'Snake'}
]
initialSelectedKeys: ['Kangaroo']
getKey: (item) => itemname
});
function removeItem() {
// Removing the list item will also remove it from the selection state.
listremove('Kangaroo');
}
<ListBox
items= listitems
selectedKeys= listselectedKeys
onSelectionChange= listsetSelectedKeys>
(item) => <Item key= itemname> itemname</Item>
</ListBox>
let list = useListData({
initialItems: [
{name: 'Aardvark'}
{name: 'Kangaroo'}
{name: 'Snake'}
]
initialSelectedKeys: [
'Kangaroo'
]
getKey: (item) =>
itemname
});
function removeItem() {
// Removing the list item will also remove it from the selection state.
listremove(
'Kangaroo'
);
}
<ListBox
items= listitems
selectedKeys=
listselectedKeys
onSelectionChange=
listsetSelectedKeys
>
(item) => (
<Item
key= itemname>
itemname
</Item>
)
</ListBox>
For more information, see useListData and useTreeData.
Select All#
Some components support a checkbox to select all items in the collection, or a keyboard shortcut like ⌘ Cmd + A. This represents a selection of all items in the collection, regardless of whether or not all items have been loaded from the network. For example, when using a component with infinite scrolling support, the user will be unaware that all items are not yet loaded because it loads more transparently to them as they scroll down. For this reason, it makes sense for select all to represent all items, not just the loaded ones.
When a select all event occurs, onSelectionChange
is called with the string "all"
rather than a set of selected keys. selectedKeys
and defaultSelectedKeys
can also be set to "all"
to programmatically select all items. This represents all items in the collection,
whether currently loaded or not. The application must adjust its handling of bulk actions in this case to apply to the entire collection
rather than only the keys available to it locally.
let [selectedKeys setSelectedKeys] = useState(new Set());
function performBulkAction() {
if (selectedKeys === 'all') {
// perform action on all items
} else {
// perform action on selected items in selectedKeys
}
}
<ListBox
items= items
selectedKeys= selectedKeys
onSelectionChange= setSelectedKeys>
(item) => <Item> itemname</Item>
</ListBox>
let [selectedKeys setSelectedKeys] = useState(new Set());
function performBulkAction() {
if (selectedKeys === 'all') {
// perform action on all items
} else {
// perform action on selected items in selectedKeys
}
}
<ListBox
items= items
selectedKeys= selectedKeys
onSelectionChange= setSelectedKeys>
(item) => <Item> itemname</Item>
</ListBox>
let [
selectedKeys
setSelectedKeys
] = useState(new Set());
function performBulkAction() {
if (
selectedKeys ===
'all'
) {
// perform action on all items
} else {
// perform action on selected items in selectedKeys
}
}
<ListBox
items= items
selectedKeys=
selectedKeys
onSelectionChange=
setSelectedKeys
>
(item) => (
<Item>
itemname
</Item>
)
</ListBox>