Ark UI Logo
Collections
List selection

List Selection

Used for managing selection state in list collections.

The useListSelection hook manages selection state in lists and collections. It supports single and multiple selection modes with operations like select, deselect, toggle, and clear.

import { createListCollection, useListSelection } from '@ark-ui/react/collection'

const collection = createListCollection({
  items: [
    { label: 'Apple', value: 'apple' },
    { label: 'Banana', value: 'banana' },
    { label: 'Cherry', value: 'cherry' },
  ],
})

const selection = useListSelection({
  collection,
  selectionMode: 'single',
  deselectable: true,
})

console.log(selection.selectedValues) // ['apple', 'banana', 'cherry']

Examples

Basic

By default, the hook supports single selection mode that can be deselected.

Set deselectable to false to prevent deselecting the current selection.

import { createListCollection, useListSelection } from '@ark-ui/react/collection'

export const ListSelection = () => {
  const collection = createListCollection({
    items: ['React', 'Vue', 'Angular'],
  })

  const selection = useListSelection({
    collection,
  })

  return (
    <div>
      <pre>{JSON.stringify(selection.selectedValues)}</pre>
      {collection.items.map((item) => (
        <label
          key={item}
          style={{
            display: 'flex',
            alignItems: 'center',
            gap: 8,
            userSelect: 'none',
            backgroundColor: selection.isSelected(item) ? 'lightblue' : 'white',
          }}
        >
          <input type="checkbox" checked={selection.isSelected(item)} onChange={() => selection.select(item)} />
          <span>{item}</span>
        </label>
      ))}
    </div>
  )
}

Multiple Selection

Set selectionMode to multiple to allow multiple items to be selected.

import { createListCollection, useListSelection } from '@ark-ui/react/collection'

export const ListSelectionMultiple = () => {
  const collection = createListCollection({
    items: ['React', 'Vue', 'Angular', 'Svelte', 'Solid'],
  })

  const selection = useListSelection({
    collection,
    selectionMode: 'multiple',
  })

  const handleSelectAll = () => {
    if (selection.isAllSelected()) {
      selection.clear()
    } else {
      selection.setSelectedValues(collection.getValues())
    }
  }

  return (
    <div>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 16 }}>
        <button onClick={handleSelectAll}>{selection.isAllSelected() ? 'Deselect All' : 'Select All'}</button>
        <span>
          {selection.selectedValues.length} of {collection.items.length} selected
        </span>
      </div>

      {collection.items.map((item) => (
        <label
          key={item}
          style={{
            display: 'flex',
            alignItems: 'center',
            gap: 8,
            userSelect: 'none',
            backgroundColor: selection.isSelected(item) ? 'lightblue' : 'white',
          }}
        >
          <input type="checkbox" checked={selection.isSelected(item)} onChange={() => selection.select(item)} />
          <span>{item}</span>
        </label>
      ))}
    </div>
  )
}

Range Selection

Here's an example of how to implement range selection that extends the selection from the first selected item to the clicked item.

import { createListCollection, useListSelection } from '@ark-ui/react/collection'

export const ListSelectionRange = () => {
  const collection = createListCollection({
    items: [
      { value: 'react', label: 'React' },
      { value: 'vue', label: 'Vue' },
      { value: 'angular', label: 'Angular' },
      { value: 'svelte', label: 'Svelte' },
      { value: 'solid', label: 'Solid' },
      { value: 'preact', label: 'Preact' },
      { value: 'qwik', label: 'Qwik' },
      { value: 'lit', label: 'Lit' },
    ],
  })

  const selection = useListSelection({
    collection,
    selectionMode: 'multiple',
  })

  const handleItemClick = (value: string, event: React.MouseEvent) => {
    if (event.shiftKey && selection.firstSelectedValue) {
      // Extend selection from first selected to clicked item
      selection.extend(selection.firstSelectedValue, value)
    } else if (event.ctrlKey || event.metaKey) {
      // Toggle individual item
      selection.toggle(value)
    } else {
      // Replace selection with clicked item
      selection.replace(value)
    }
  }

  return (
    <div>
      <div style={{ marginBottom: 16 }}>
        <p>
          <strong>Instructions:</strong>
        </p>
        <ul style={{ margin: '8px 0', paddingLeft: 20 }}>
          <li>Click to select single item</li>
          <li>Ctrl/Cmd + Click to toggle individual items</li>
          <li>Shift + Click to select range from first selected item</li>
        </ul>
      </div>

      {collection.items.map((item) => (
        <label
          key={item.value}
          style={{
            backgroundColor: selection.isSelected(item.value) ? '#e2e8f0' : 'transparent',
            padding: '8px 12px',
            cursor: 'pointer',
            userSelect: 'none',
            border: '1px solid #e2e8f0',
            marginBottom: 2,
          }}
        >
          <input
            type="checkbox"
            checked={selection.isSelected(item.value)}
            onClick={(e) => handleItemClick(item.value, e)}
          />
          {item.label}
        </label>
      ))}
    </div>
  )
}

API Reference

Props

  • collection (ListCollection<T>) - The collection to manage selection for
  • selectionMode ('single' | 'multiple' | 'none', default: 'single') - The selection mode
  • deselectable (boolean, default: true) - Whether selected items can be deselected
  • initialSelectedValues (string[], default: []) - Initial selected values
  • resetOnCollectionChange (boolean, default: false) - Whether to reset selection when collection changes

Return Value

The hook returns an object with the following properties and methods:

State Properties

  • selectedValues (string[]) - Array of currently selected values
  • isEmpty (boolean) - Whether no items are selected
  • firstSelectedValue (string | null) - The first selected value in collection order
  • lastSelectedValue (string | null) - The last selected value in collection order

Query Methods

  • isSelected ((value: string | null) => boolean) - Check if a value is selected
  • canSelect ((value: string) => boolean) - Check if a value can be selected
  • isAllSelected (() => boolean) - Check if all items are selected
  • isSomeSelected (() => boolean) - Check if some items are selected

Selection Methods

  • select ((value: string, forceToggle?: boolean) => void) - Select a value
  • deselect ((value: string) => void) - Deselect a value
  • toggle ((value: string) => void) - Toggle selection of a value
  • replace ((value: string | null) => void) - Replace selection with a single value
  • extend ((anchorValue: string, targetValue: string) => void) - Extend selection from anchor to target
  • setSelectedValues ((values: string[]) => void) - Set the selected values
  • setSelection ((values: string[]) => void) - Set the selection (alias for setSelectedValues)
  • clear (() => void) - Clear all selections
  • resetSelection (() => void) - Reset selection to initial state

Design System Support

Expert design system support from the creators of Ark UI

Get Support