Table State
Selection
Selection is a list of row ids in the state, rendered as native checkboxes or radios. Which rows a select-all covers, which rows can be selected at all, and what the selection means are the application's decisions.
- Fixture
- Benchmark
On this page
The controls are native inputs, so the browser provides focus, Space to toggle, the checked
state and the radio group semantics. Multiple selection renders one checkbox per row and a
header checkbox with an indeterminate state; single selection renders radios that share the name <id>-selection, which is why selection="single" needs the id prop. Each row control is labelled with the selectRow message and the
row id; the selected count is announced through a polite live region.
selectionScope decides what the header checkbox and selectAll() act
on: the rows on the current page, or every filtered row across pages. Rows that fail isRowSelectable render a disabled control and are excluded from both. Ids stay in the
state when a row scrolls off the page or is filtered out, so a selection survives navigation and search.
Multiple selection
Single or multiple selection, disabled records and page or filtered select-all scope.
Amara Okafor | Active | Engineering | $4,501 | |
Jonas Lindqvist | Active | Design | $12,420 | |
Mei Tanaka | Away | Operations | $20,339 | |
Rafael Duarte | Invited | Growth | $28,258 | |
Selin Aydın | Active | Engineering | $36,177 | |
Noah Brenner | Active | Design | $44,096 |
[]
<script lang="ts">
import { DataTable, defaultState, type TableState } from '@svelte-lean/table';
import '@svelte-lean/styles/radio-group.css';
import { memberColumns, pick } from '$lib/demo/columns';
import { people } from '$lib/demo/data';
const data = people(12);
const columns = pick(memberColumns(), ['name', 'status', 'team', 'revenue']);
let mode = $state<'multiple' | 'single'>('multiple');
let scope = $state<'page' | 'filtered'>('filtered');
let tableState = $state<Partial<TableState>>(defaultState({ pageSize: 6 }));
</script>
<fieldset data-slean="radio-group">
<legend>Mode</legend>
<label><input type="radio" name="mode" value="multiple" bind:group={mode} /> multiple</label>
<label><input type="radio" name="mode" value="single" bind:group={mode} /> single</label>
</fieldset>
<fieldset data-slean="radio-group">
<legend>Select-all scope</legend>
<label><input type="radio" name="scope" value="page" bind:group={scope} /> page</label>
<label><input type="radio" name="scope" value="filtered" bind:group={scope} /> filtered</label>
</fieldset>
<button type="button" data-slean="button" data-variant="outline" onclick={() => (tableState = { ...tableState, selection: [] })}>Clear</button>
<!-- id names the radio group in single mode: <id>-selection. Invited members cannot be selected. -->
<DataTable
id="members"
{data}
{columns}
getRowId={(row) => row.id}
bind:state={tableState}
selection={mode}
selectionScope={scope}
isRowSelectable={(row) => row.status !== 'Invited'}
searchable
label="Members"
/>
<pre>{JSON.stringify(tableState.selection)}</pre>- Switching to single mode keeps the list; the next selection replaces it with one id.
- The pre element prints
state.selection; nothing else about the rows changes.
Keyboard
| Key | When | Result |
|---|---|---|
| Tab | in the body | Moves through the row controls in order. |
| Space | on a checkbox | Toggles the row; on the header checkbox, selects or clears the scope. |
| ArrowUp/ArrowDown | on a radio | Moves the selection to the previous or next selectable row (native radio group). |
API
| Name | Of | Type | Default | Description |
|---|---|---|---|---|
selection | Controls | false | 'single' | 'multiple' | false | Adds a radio or checkbox column. 'single' needs the id prop for the radio group name. |
selectionScope | Controls | 'page' | 'filtered' | 'page' | Rows that select-all and the header checkbox consider: the current page or every filtered row. |
isRowSelectable | Controls | (row: T) => boolean | () => true | Disables the selection control of rows that fail the rule. |
hideSelectAll | Controls | boolean | false | Hides the header checkbox of multiple selection; the header cell keeps the selectionHeader text for assistive technology. |
id | Data and identity | string | undefined | id of the root element. With selection: 'single' it also names the row radios (<id>-selection) so they form one native radio group. Authored, never generated. |
selection | TableState | RowId[] | [] | Selected row ids. |
selectAll | TableMessages | string | 'Select all eligible rows' | Label of the header checkbox. |
selectRow | TableMessages | string | 'Select row' | Prefix of each row control label (followed by the row id). |
selected | TableMessages | (count: number) => string | (count) => `${count} selected` | The live selection count in the toolbar. |
toggleSelection | Table | (id: RowId, selected?: boolean) => void | – | Toggles one row; in 'single' mode the row replaces the selection. |
selectAll | Table | (ids?: readonly RowId[], selected?: boolean) => void | – | Selects or clears many rows; defaults to selectable and to select unless all are selected. |
selectable | Table | RowId[] | – | Ids a selection control may act on within selectionScope. |
toggleSelection | Root entry | (current: RowId[], eligible: RowId[], select?: boolean) => RowId[] | – | Adds or removes the eligible ids; without select it selects unless all are selected. |