Skip to content

Row Selection

useRowSelection() — dataset-agnostic click / Shift-click row selection — works with VirtualList, VirtualTable, or any plain array. Not tied to a specific component: pair isSelected/toggle with whichever row-index slot scope your component exposes.

ts
function useRowSelection<T>(options: UseRowSelectionOptions<T>): UseRowSelectionReturn<T>

Options

items

Ref<T[]> | ComputedRef<T[]>

Reactive items array.

getKey

(item: T, index: number) => string | number · default: item.id ?? index

Identity used for the selection set.

multiple

boolean · default: true

false restricts to a single selected row; a new toggle call replaces the selection instead of adding to it.

Return value

selectedKeys

Readonly<Ref<Set<string | number>>>

Currently selected keys.

selectedItems

ComputedRef<T[]>

Currently selected items, derived from items + selectedKeys.

isSelected

(item: T, index: number) => boolean

Whether a row is selected.

toggle

(item: T, index: number, event?: MouseEvent | KeyboardEvent) => void

Toggle a row. event.shiftKey fills the range from the last-toggled row to this one (Gmail-checkbox convention), on top of whatever's already selected.

selectAll

() => void

Select every row in items.

clearSelection

() => void

Clear the selection and reset the shift-range anchor.

Example

vue
<script setup lang="ts">
import { ref } from 'vue'
import { VirtualList, useRowSelection } from 'vue-virtual-scroller-kit'

interface Row {
  id: number
  label: string
}
const items = ref<Row[]>(Array.from({ length: 1000 }, (_, i) => ({ id: i, label: `Row ${i + 1}` })))

const selection = useRowSelection<Row>({ items })
</script>

<template>
  <VirtualList :items="items" key-field="id" :estimated-item-size="40" style="height: 500px">
    <template #default="{ item, index }">
      <label>
        <input
          type="checkbox"
          :checked="selection.isSelected(item, index)"
          @click="selection.toggle(item, index, $event)"
        />
        {{ item.label }}
      </label>
    </template>
  </VirtualList>
  <p>{{ selection.selectedItems.value.length }} selected</p>
</template>

Click toggles one row in place; Shift+click fills the range from the last-toggled row. For VirtualTable, pair this with the index now available on the #cell slot — see the row-selection example on the VirtualTable page.