# List Selection

URL: https://ark-ui.com/docs/collections/list-selection
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/collections/list-selection.mdx

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.

```tsx
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.

**Example: list-selection/basic**

#### React

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

export const Basic = () => {
  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>
  )
}

```

#### Solid

```tsx
import { createListCollection, useListSelection } from '@ark-ui/solid/collection'
import { For } from 'solid-js'

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

  const selection = useListSelection({
    collection,
  })

  return (
    <div>
      <pre>{JSON.stringify(selection.selectedValues())}</pre>
      <For each={collection.items}>
        {(item) => (
          <label
            style={{
              display: 'flex',
              'align-items': 'center',
              gap: '8px',
              'user-select': 'none',
              'background-color': selection.isSelected(item) ? 'lightblue' : 'white',
            }}
          >
            <input type="checkbox" checked={selection.isSelected(item)} onChange={() => selection.select(item)} />
            <span>{item}</span>
          </label>
        )}
      </For>
    </div>
  )
}

```

#### Vue

```vue
<script setup lang="ts">
import { createListCollection, useListSelection } from '@ark-ui/vue/collection'

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

const selection = useListSelection({
  collection,
})
</script>

<template>
  <div>
    <pre>{{ JSON.stringify(selection.selectedValues.value) }}</pre>
    <label
      v-for="item in collection.items"
      :key="item"
      :style="{
        display: 'flex',
        alignItems: 'center',
        gap: '8px',
        userSelect: 'none',
        backgroundColor: selection.isSelected(item) ? 'lightblue' : 'white',
      }"
    >
      <input type="checkbox" :checked="selection.isSelected(item)" @change="selection.select(item)" />
      <span>{{ item }}</span>
    </label>
  </div>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { useListSelection, createListCollection } from '@ark-ui/svelte/collection'

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

  const selection = useListSelection({
    collection,
  })
</script>

<div>
  <pre>{JSON.stringify(selection.selectedValues())}</pre>
  {#each collection.items as item (item)}
    <label
      style:display="flex"
      style:align-items="center"
      style:gap="8px"
      style:user-select="none"
      style:background-color={selection.isSelected(item) ? 'lightblue' : 'white'}
    >
      <input type="checkbox" checked={selection.isSelected(item)} onchange={() => selection.select(item)} />
      <span>{item}</span>
    </label>
  {/each}
</div>

```

### Multiple Selection

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

**Example: list-selection/multiple**

#### React

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

export const Multiple = () => {
  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>
  )
}

```

#### Solid

```tsx
import { createListCollection, useListSelection } from '@ark-ui/solid/collection'
import { For } from 'solid-js'

export const Multiple = () => {
  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={{ 'margin-bottom': '16px', display: 'flex', 'align-items': 'center', gap: '16px' }}>
        <button onClick={handleSelectAll}>{selection.isAllSelected() ? 'Deselect All' : 'Select All'}</button>
        <span>
          {selection.selectedValues().length} of {collection.items.length} selected
        </span>
      </div>

      <For each={collection.items}>
        {(item) => (
          <label
            style={{
              display: 'flex',
              'align-items': 'center',
              gap: '8px',
              'user-select': 'none',
              'background-color': selection.isSelected(item) ? 'lightblue' : 'white',
            }}
          >
            <input type="checkbox" checked={selection.isSelected(item)} onChange={() => selection.select(item)} />
            <span>{item}</span>
          </label>
        )}
      </For>
    </div>
  )
}

```

#### Vue

```vue
<script setup lang="ts">
import { createListCollection, useListSelection } from '@ark-ui/vue/collection'

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())
  }
}
</script>

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

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

```

#### Svelte

```svelte
<script lang="ts">
  import { createListCollection, useListSelection } from '@ark-ui/svelte/collection'

  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())
    }
  }
</script>

<div>
  <div style="margin-bottom: 16px; display: flex; align-items: center; gap: 16px;">
    <button onclick={handleSelectAll}>
      {selection.isAllSelected() ? 'Deselect All' : 'Select All'}
    </button>
    <span>
      {selection.selectedValues().length} of {collection.items.length} selected
    </span>
  </div>

  {#each collection.items as item (item)}
    <label
      style="display: flex; align-items: center; gap: 8px; user-select: none;"
      style:background-color={selection.isSelected(item) ? 'lightblue' : 'white'}
    >
      <input type="checkbox" checked={selection.isSelected(item)} onchange={() => selection.select(item)} />
      <span>{item}</span>
    </label>
  {/each}
</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.

**Example: list-selection/range**

#### React

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

export const Range = () => {
  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>
  )
}

```

#### Solid

```tsx
import { createListCollection, useListSelection } from '@ark-ui/solid/collection'
import { For } from 'solid-js'

export const Range = () => {
  const 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 collection = createListCollection({ items })
  const selection = useListSelection({
    collection,
    selectionMode: 'multiple',
  })

  const handleItemClick = (value: string, event: MouseEvent) => {
    const firstSelectedValue = selection.firstSelectedValue()
    if (event.shiftKey && firstSelectedValue) {
      // Extend selection from first selected to clicked item
      selection.extend(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={{ 'margin-bottom': '16px' }}>
        <p>
          <strong>Instructions:</strong>
        </p>
        <ul style={{ margin: '8px 0', 'padding-left': '20px' }}>
          <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>

      <For each={collection.items}>
        {(item) => (
          <label
            style={{
              'background-color': selection.isSelected(item.value) ? '#e2e8f0' : 'transparent',
              padding: '8px 12px',
              cursor: 'pointer',
              'user-select': 'none',
              border: '1px solid #e2e8f0',
              'margin-bottom': '2px',
            }}
          >
            <input
              type="checkbox"
              checked={selection.isSelected(item.value)}
              onClick={(e) => handleItemClick(item.value, e)}
            />
            {item.label}
          </label>
        )}
      </For>
    </div>
  )
}

```

#### Vue

```vue
<script setup lang="ts">
import { createListCollection, useListSelection } from '@ark-ui/vue/collection'

const 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 collection = createListCollection({ items })
const selection = useListSelection({
  collection,
  selectionMode: 'multiple',
})

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

<template>
  <div>
    <div style="margin-bottom: 16px">
      <p><strong>Instructions:</strong></p>
      <ul style="margin: 8px 0; padding-left: 20px">
        <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>

    <div
      v-for="item in collection.items"
      :key="item.value"
      @click="(e) => handleItemClick(item.value, e)"
      :style="{
        backgroundColor: selection.isSelected(item.value) ? '#e2e8f0' : 'transparent',
        padding: '8px 12px',
        cursor: 'pointer',
        userSelect: 'none',
        border: '1px solid #e2e8f0',
        marginBottom: '2px',
      }"
    >
      {{ item.label }}
    </div>
  </div>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { createListCollection, useListSelection } from '@ark-ui/svelte/collection'

  const 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 collection = createListCollection({ items })
  const selection = useListSelection({
    collection,
    selectionMode: 'multiple',
  })

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

<div>
  <div style="margin-bottom: 16px;">
    <p><strong>Instructions:</strong></p>
    <ul style="margin: 8px 0; padding-left: 20px;">
      <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>

  {#each collection.items as item (item.value)}
    <label
      style="padding: 8px 12px; cursor: pointer; user-select: none; border: 1px solid #e2e8f0; margin-bottom: 2px;"
      style:background-color={selection.isSelected(item.value) ? '#e2e8f0' : 'transparent'}
    >
      <input
        type="checkbox"
        checked={selection.isSelected(item.value)}
        onclick={(e) => handleItemClick(item.value, e)}
      />
      {item.label}
    </label>
  {/each}
</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