# useTableSelection

## Usage

Hook that returns a TablePlugin implementing row selection with checkboxes, select-all, and `aria-selected`. The table adds the checkbox column itself. Selection state is read through the getters on every render, so the checkbox cells follow whatever reactive state those getters read; there is no provider to wrap the table in.

```ts
import { useTableSelection } from '@astryx-vue/core/Table'
```

Two getters decide what a row looks like. `getIsItemSelectable` removes the checkbox from a row that has nothing to select, and `getIsItemEnabled` keeps the checkbox in place but disabled, for a row that cannot be picked right now.

```ts
const selection = useTableSelection({
  getIsItemSelected: item => selectedKeys.value.has(item.id),
  onSelectItem: ({ item, isSelected }) => { /* ... */ },
  onSelectAll: ({ isAllSelected }) => { /* ... */ },
  getIsAllSelected: () => /* ... */ false,
  getIsItemSelectable: item => item.role !== 'System',
  getIsItemEnabled: item => item.status !== 'Locked',
})
```

`hasRowHighlight` only controls the accent wash on checked rows. `aria-selected` stays on them either way, so the selection is still announced when the surrounding UI already uses row background for something else.

## Examples

### useTableSelection — Row Selection

Table with row selection checkboxes and a select-all header checkbox.

```vue
<script setup lang="ts">
import type { TableColumn } from '@astryx-vue/core/Table'
import { proportional, Table, useTableSelection, useTableSelectionState } from '@astryx-vue/core/Table'
import { ref } from 'vue'

interface User extends Record<string, unknown> {
  id: string
  name: string
  email: string
  role: string
}

const users: User[] = [
  { id: '1', name: 'Alice', email: 'alice@example.com', role: 'Engineer' },
  { id: '2', name: 'Bob', email: 'bob@example.com', role: 'Designer' },
  { id: '3', name: 'Charlie', email: 'charlie@example.com', role: 'Manager' },
  { id: '4', name: 'Diana', email: 'diana@example.com', role: 'Engineer' },
  { id: '5', name: 'Eve', email: 'eve@example.com', role: 'Admin' },
]

const columns: TableColumn<User>[] = [
  { key: 'name', header: 'Name', width: proportional(1) },
  { key: 'email', header: 'Email', width: proportional(2) },
  { key: 'role', header: 'Role', width: proportional(1) },
]

const selectedKeys = ref(new Set<string>())
const { selectionConfig } = useTableSelectionState<User>({
  data: users,
  idKey: 'id',
  selectedKeys,
  setSelectedKeys(keys) {
    selectedKeys.value = keys
  },
})
const selectionPlugin = useTableSelection<User>(selectionConfig)
</script>

<template>
  <Table
    :data="users"
    :columns="columns"
    id-key="id"
    :plugins="{ selection: selectionPlugin }"
  />
</template>
```

## Properties

The config is a `MaybeRefOrGetter`, so pass a getter or a ref to keep the plugin on the current values.

## Parameters

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `getIsItemSelected` | `(item: T) => boolean` | — | Returns whether the given item is currently selected. |
| `onSelectItem` | `(event: { item: T; isSelected: boolean }) => void` | — | Called when a row checkbox is toggled. `isSelected` is the new desired state. |
| `onSelectAll` | `(event: { isAllSelected: boolean }) => void` | — | Called when the select-all header checkbox is toggled. |
| `getIsAllSelected` | `() => boolean` | — | Returns whether all selectable items are currently selected. |
| `getIsIndeterminate` | `() => boolean` | `() => false` | Returns whether selection is partial (some but not all). Renders the select-all checkbox in indeterminate state. |
| `getIsItemSelectable` | `(item: T) => boolean` | `() => true` | Returns whether a row should show a checkbox. Non-selectable rows render nothing in the selection cell. |
| `getIsItemEnabled` | `(item: T) => boolean` | `() => true` | Returns whether a row checkbox is interactive. Disabled rows keep their checkbox, rendered disabled, so the selection column stays aligned. |
| `getRowLabel` | `(item: T) => string` | — | Derives a human-readable identity for a row; the row checkbox's hidden label becomes `Select ${getRowLabel(item)}` so screen readers announce which row each checkbox selects. Falls back to "Select row" when omitted. |
| `hasRowHighlight` | `boolean` | `true` | Paints checked rows with the accent wash. Set false when the surrounding UI already uses row background to mean something else (a row open in a detail panel, say). Only the background is dropped: `aria-selected` is still set on checked rows either way. |

## Returns

| Field | Type | Description |
| --- | --- | --- |
| `selection` | `TableSelectionContribution` | The plugin contribution the table reads. Put the whole plugin under any key of the `plugins` prop; the table picks up the one entry that has `selection`. |
| `selection.isAllSelected` | `() => boolean` | Wraps `getIsAllSelected`. |
| `selection.isIndeterminate` | `() => boolean` | Wraps `getIsIndeterminate`, or `false` when it is omitted. |
| `selection.isSelected` | `(row: T) => boolean` | Wraps `getIsItemSelected`. |
| `selection.isSelectable` | `(row: T) => boolean` | Wraps `getIsItemSelectable`, or `true` when it is omitted. |
| `selection.isEnabled` | `(row: T) => boolean` | Wraps `getIsItemEnabled`, or `true` when it is omitted. |
| `selection.selectAll` | `(selected: boolean) => void` | Calls `onSelectAll` with `{ isAllSelected: selected }`. |
| `selection.selectRow` | `(row: T, selected: boolean) => void` | Calls `onSelectItem` with `{ item: row, isSelected: selected }`. |
| `selection.rowLabel` | `(row: T) => string` | Wraps `getRowLabel`, or an empty string when it is omitted. |
| `selection.hasRowHighlight` | `boolean \| undefined` | The value from the config. Anything other than `false` keeps the wash. |
