# List Selection

URL: https://ark-ui.com/docs/collections/list-selection
LLM: https://ark-ui.com/llms.txt/collections/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.

```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'
import styles from 'styles/list-selection.module.css'

export const Basic = () => {
  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
    ],
  })

  const selection = useListSelection({ collection })

  return (
    <div className={styles.Root}>
      <output>Selected: {selection.selectedValues.join(', ') || 'None'}</output>
      {collection.items.map((item) => (
        <label key={item.value} className={styles.Item} data-selected={selection.isSelected(item.value) || undefined}>
          <input
            type="checkbox"
            className={styles.Checkbox}
            checked={selection.isSelected(item.value)}
            onChange={() => selection.select(item.value)}
          />
          <span className={styles.ItemText}>{item.label}</span>
        </label>
      ))}
    </div>
  )
}

```

#### Solid

```tsx
import { createListCollection, useListSelection } from '@ark-ui/solid/collection'
import { For } from 'solid-js'
import styles from 'styles/list-selection.module.css'

export const Basic = () => {
  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
    ],
  })

  const selection = useListSelection({ collection })

  return (
    <div class={styles.Root}>
      <output>Selected: {selection.selectedValues().join(', ') || 'None'}</output>
      <For each={collection.items}>
        {(item) => (
          <label class={styles.Item} data-selected={selection.isSelected(item.value) || undefined}>
            <input
              type="checkbox"
              class={styles.Checkbox}
              checked={selection.isSelected(item.value)}
              onChange={() => selection.select(item.value)}
            />
            <span class={styles.ItemText}>{item.label}</span>
          </label>
        )}
      </For>
    </div>
  )
}

```

#### Vue

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

const collection = createListCollection({
  items: [
    { label: 'React', value: 'react' },
    { label: 'Vue', value: 'vue' },
    { label: 'Angular', value: 'angular' },
    { label: 'Svelte', value: 'svelte' },
  ],
})

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

<template>
  <div :class="styles.Root">
    <output>Selected: {{ selection.selectedValues.value.join(', ') || 'None' }}</output>
    <label
      v-for="item in collection.items"
      :key="item.value"
      :class="styles.Item"
      :data-selected="selection.isSelected(item.value) || undefined"
    >
      <input
        type="checkbox"
        :class="styles.Checkbox"
        :checked="selection.isSelected(item.value)"
        @change="selection.select(item.value)"
      />
      <span :class="styles.ItemText">{{ item.label }}</span>
    </label>
  </div>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { createListCollection, useListSelection } from '@ark-ui/svelte/collection'
  import styles from 'styles/list-selection.module.css'

  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
    ],
  })

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

<div class={styles.Root}>
  <output>Selected: {selection.selectedValues().join(', ') || 'None'}</output>
  {#each collection.items as item (item.value)}
    <label class={styles.Item} data-selected={selection.isSelected(item.value) || undefined}>
      <input
        type="checkbox"
        class={styles.Checkbox}
        checked={selection.isSelected(item.value)}
        onchange={() => selection.select(item.value)}
      />
      <span class={styles.ItemText}>{item.label}</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'
import styles from 'styles/list-selection.module.css'

export const Multiple = () => {
  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
      { label: 'Solid', value: 'solid' },
    ],
  })

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

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

  return (
    <div className={styles.Root}>
      <div className={styles.Header}>
        <span className={styles.Count}>
          {selection.selectedValues.length} of {collection.items.length} selected
        </span>
        <button type="button" className={styles.SelectAllButton} onClick={handleSelectAll}>
          {selection.isAllSelected() ? 'Deselect all' : 'Select all'}
        </button>
      </div>
      {collection.items.map((item) => (
        <label key={item.value} className={styles.Item} data-selected={selection.isSelected(item.value) || undefined}>
          <input
            type="checkbox"
            className={styles.Checkbox}
            checked={selection.isSelected(item.value)}
            onChange={() => selection.select(item.value)}
          />
          <span className={styles.ItemText}>{item.label}</span>
        </label>
      ))}
    </div>
  )
}

```

#### Solid

```tsx
import { createListCollection, useListSelection } from '@ark-ui/solid/collection'
import { For } from 'solid-js'
import styles from 'styles/list-selection.module.css'

export const Multiple = () => {
  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
      { label: 'Solid', value: 'solid' },
    ],
  })

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

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

  return (
    <div class={styles.Root}>
      <div class={styles.Header}>
        <span class={styles.Count}>
          {selection.selectedValues().length} of {collection.items.length} selected
        </span>
        <button type="button" class={styles.SelectAllButton} onClick={handleSelectAll}>
          {selection.isAllSelected() ? 'Deselect all' : 'Select all'}
        </button>
      </div>
      <For each={collection.items}>
        {(item) => (
          <label class={styles.Item} data-selected={selection.isSelected(item.value) || undefined}>
            <input
              type="checkbox"
              class={styles.Checkbox}
              checked={selection.isSelected(item.value)}
              onChange={() => selection.select(item.value)}
            />
            <span class={styles.ItemText}>{item.label}</span>
          </label>
        )}
      </For>
    </div>
  )
}

```

#### Vue

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

const collection = createListCollection({
  items: [
    { label: 'React', value: 'react' },
    { label: 'Vue', value: 'vue' },
    { label: 'Angular', value: 'angular' },
    { label: 'Svelte', value: 'svelte' },
    { label: 'Solid', value: 'solid' },
  ],
})

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

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

<template>
  <div :class="styles.Root">
    <div :class="styles.Header">
      <span :class="styles.Count">
        {{ selection.selectedValues.value.length }} of {{ collection.items.length }} selected
      </span>
      <button type="button" :class="styles.SelectAllButton" @click="handleSelectAll">
        {{ selection.isAllSelected() ? 'Deselect all' : 'Select all' }}
      </button>
    </div>
    <label
      v-for="item in collection.items"
      :key="item.value"
      :class="styles.Item"
      :data-selected="selection.isSelected(item.value) || undefined"
    >
      <input
        type="checkbox"
        :class="styles.Checkbox"
        :checked="selection.isSelected(item.value)"
        @change="selection.select(item.value)"
      />
      <span :class="styles.ItemText">{{ item.label }}</span>
    </label>
  </div>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { createListCollection, useListSelection } from '@ark-ui/svelte/collection'
  import styles from 'styles/list-selection.module.css'

  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
      { label: 'Solid', value: 'solid' },
    ],
  })

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

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

<div class={styles.Root}>
  <div class={styles.Header}>
    <span class={styles.Count}>
      {selection.selectedValues().length} of {collection.items.length} selected
    </span>
    <button type="button" class={styles.SelectAllButton} onclick={handleSelectAll}>
      {selection.isAllSelected() ? 'Deselect all' : 'Select all'}
    </button>
  </div>
  {#each collection.items as item (item.value)}
    <label class={styles.Item} data-selected={selection.isSelected(item.value) || undefined}>
      <input
        type="checkbox"
        class={styles.Checkbox}
        checked={selection.isSelected(item.value)}
        onchange={() => selection.select(item.value)}
      />
      <span class={styles.ItemText}>{item.label}</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'
import styles from 'styles/list-selection.module.css'

export const Range = () => {
  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
      { label: 'Solid', value: 'solid' },
    ],
  })

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

  const handleItemClick = (value: string, event: React.MouseEvent) => {
    if (event.shiftKey && selection.firstSelectedValue) {
      selection.extend(selection.firstSelectedValue, value)
    } else if (event.ctrlKey || event.metaKey) {
      selection.toggle(value)
    } else {
      selection.replace(value)
    }
  }

  return (
    <div className={styles.Root}>
      <output>Selected: {selection.selectedValues.join(', ') || 'None'}</output>
      {collection.items.map((item) => (
        <label
          key={item.value}
          className={styles.Item}
          data-selected={selection.isSelected(item.value) || undefined}
          onClick={(e) => handleItemClick(item.value, e)}
        >
          <input type="checkbox" className={styles.Checkbox} checked={selection.isSelected(item.value)} />
          <span className={styles.ItemText}>{item.label}</span>
        </label>
      ))}
      <p className={styles.HelperText}>Click to select • Shift+Click for range • Cmd/Ctrl+Click to toggle</p>
    </div>
  )
}

```

#### Solid

```tsx
import { createListCollection, useListSelection } from '@ark-ui/solid/collection'
import { For } from 'solid-js'
import styles from 'styles/list-selection.module.css'

export const Range = () => {
  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
      { label: 'Solid', value: 'solid' },
    ],
  })

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

  const handleItemClick = (value: string, event: MouseEvent) => {
    const firstSelectedValue = selection.firstSelectedValue()
    if (event.shiftKey && firstSelectedValue) {
      selection.extend(firstSelectedValue, value)
    } else if (event.ctrlKey || event.metaKey) {
      selection.toggle(value)
    } else {
      selection.replace(value)
    }
  }

  return (
    <div class={styles.Root}>
      <output>Selected: {selection.selectedValues().join(', ') || 'None'}</output>
      <For each={collection.items}>
        {(item) => (
          <label
            class={styles.Item}
            data-selected={selection.isSelected(item.value) || undefined}
            onClick={(e) => handleItemClick(item.value, e)}
          >
            <input type="checkbox" class={styles.Checkbox} checked={selection.isSelected(item.value)} />
            <span class={styles.ItemText}>{item.label}</span>
          </label>
        )}
      </For>
      <p class={styles.HelperText}>Click to select • Shift+Click for range • Cmd/Ctrl+Click to toggle</p>
    </div>
  )
}

```

#### Vue

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

const collection = createListCollection({
  items: [
    { label: 'React', value: 'react' },
    { label: 'Vue', value: 'vue' },
    { label: 'Angular', value: 'angular' },
    { label: 'Svelte', value: 'svelte' },
    { label: 'Solid', value: 'solid' },
  ],
})

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

const handleItemClick = (value: string, event: MouseEvent) => {
  if (event.shiftKey && selection.firstSelectedValue.value) {
    selection.extend(selection.firstSelectedValue.value, value)
  } else if (event.ctrlKey || event.metaKey) {
    selection.toggle(value)
  } else {
    selection.replace(value)
  }
}
</script>

<template>
  <div :class="styles.Root">
    <output>Selected: {{ selection.selectedValues.value.join(', ') || 'None' }}</output>
    <label
      v-for="item in collection.items"
      :key="item.value"
      :class="styles.Item"
      :data-selected="selection.isSelected(item.value) || undefined"
      @click="(e: MouseEvent) => handleItemClick(item.value, e)"
    >
      <input type="checkbox" :class="styles.Checkbox" :checked="selection.isSelected(item.value)" />
      <span :class="styles.ItemText">{{ item.label }}</span>
    </label>
    <p :class="styles.HelperText">Click to select • Shift+Click for range • Cmd/Ctrl+Click to toggle</p>
  </div>
</template>

```

#### Svelte

```svelte
<script lang="ts">
  import { createListCollection, useListSelection } from '@ark-ui/svelte/collection'
  import styles from 'styles/list-selection.module.css'

  const collection = createListCollection({
    items: [
      { label: 'React', value: 'react' },
      { label: 'Vue', value: 'vue' },
      { label: 'Angular', value: 'angular' },
      { label: 'Svelte', value: 'svelte' },
      { label: 'Solid', value: 'solid' },
    ],
  })

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

  const handleItemClick = (value: string, event: MouseEvent) => {
    const firstSelectedValue = selection.firstSelectedValue()
    if (event.shiftKey && firstSelectedValue) {
      selection.extend(firstSelectedValue, value)
    } else if (event.ctrlKey || event.metaKey) {
      selection.toggle(value)
    } else {
      selection.replace(value)
    }
  }
</script>

<div class={styles.Root}>
  <output>Selected: {selection.selectedValues().join(', ') || 'None'}</output>
  {#each collection.items as item (item.value)}
    <label
      class={styles.Item}
      data-selected={selection.isSelected(item.value) || undefined}
      onclick={(e) => handleItemClick(item.value, e)}
    >
      <input type="checkbox" class={styles.Checkbox} checked={selection.isSelected(item.value)} />
      <span class={styles.ItemText}>{item.label}</span>
    </label>
  {/each}
  <p class={styles.HelperText}>Click to select • Shift+Click for range • Cmd/Ctrl+Click to toggle</p>
</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