# Row selection

> Add a checkbox column for selecting whole rows, keyed by row id so the selection survives sorting, filtering and live updates.

Row selection adds a leading checkbox column for picking whole rows, for example to act on several orders at once. The selection is a set of row ids, not positions, so it survives sorting, filtering and a live feed reordering rows. It is separate from [cell selection](https://bonguynvan.github.io/bo-grid/docs/selection/), the range a user drags over cells.

Tick a few rows, then sort a column: the same rows stay ticked. The header checkbox selects or clears every row that matches the current filter.

Example: Checkbox row selection (row-selection.svelte)

```svelte
<script lang="ts">
  import { Grid, type ColumnDef } from 'bo-grid';
  import { quotes } from './data';

  const columns: ColumnDef[] = [
    { type: 'text', key: 'symbol', header: 'Symbol', width: 100 },
    { type: 'text', key: 'name', header: 'Company', width: 150 },
    { type: 'price', key: 'price', header: 'Price', width: 96 },
    { type: 'percent', key: 'change', header: 'Chg %', flex: 1 },
  ];

  let rows = $state(quotes());
  // Ids, not positions: the selection survives sorting and filtering.
  let selected = $state<Array<string | number>>([]);
</script>

<p class="state">Selected ids: {selected.length ? selected.join(', ') : 'none'}</p>
<Grid {rows} {columns} rowSelection onRowSelectionChange={(ids) => (selected = ids)} height={260} />

<style>
  .state {
    margin: 0 0 10px;
    font-size: 12.5px;
    opacity: 0.8;
  }
</style>
```

data.ts:

```ts
// Small, fixed data for the docs' examples: every example reads the same
// symbols, so a reader compares features, not datasets.
// A type, not an interface: it then fits GridRow's index signature.
export type Quote = {
  id: number;
  symbol: string;
  name: string;
  sector: string;
  price: number;
  change: number;
  volume: number;
};

const BASE: Omit<Quote, 'id'>[] = [
  { symbol: 'VNM', name: 'Vinamilk', sector: 'Consumer', price: 68.5, change: 1.2, volume: 1_204_000 },
  { symbol: 'FPT', name: 'FPT Corp', sector: 'Technology', price: 132, change: -0.4, volume: 860_500 },
  { symbol: 'HPG', name: 'Hoa Phat', sector: 'Materials', price: 27.35, change: 0.74, volume: 3_412_900 },
  { symbol: 'VCB', name: 'Vietcombank', sector: 'Financials', price: 91.5, change: 0.55, volume: 1_986_200 },
  { symbol: 'MWG', name: 'Mobile World', sector: 'Consumer', price: 51.4, change: -1.1, volume: 2_250_400 },
  { symbol: 'SSI', name: 'SSI Securities', sector: 'Financials', price: 33.3, change: -0.45, volume: 4_104_700 },
  { symbol: 'VIC', name: 'Vingroup', sector: 'Real estate', price: 44.15, change: -0.11, volume: 1_530_100 },
  { symbol: 'GAS', name: 'PV Gas', sector: 'Energy', price: 71.8, change: 0.3, volume: 645_800 },
  { symbol: 'MSN', name: 'Masan', sector: 'Consumer', price: 76.2, change: 2.05, volume: 1_120_300 },
  { symbol: 'TCB', name: 'Techcombank', sector: 'Financials', price: 23.9, change: 0.84, volume: 5_870_000 },
  { symbol: 'VHM', name: 'Vinhomes', sector: 'Real estate', price: 41.6, change: -0.72, volume: 2_904_600 },
  { symbol: 'POW', name: 'PV Power', sector: 'Energy', price: 12.25, change: 1.66, volume: 6_315_200 },
];

/** A fresh copy of the quotes, so one example's edits never reach another. */
export function quotes(): Quote[] {
  return BASE.map((q, i) => ({ id: i + 1, ...q }));
}
```

## Turning it on

```svelte
<script lang="ts">
  let selected = $state<Array<string | number>>([]);
</script>

<Grid {rows} {columns} rowSelection onRowSelectionChange={(ids) => (selected = ids)} height={480} />
```

- Click a checkbox, or press <kbd>Space</kbd> on the focused row.
- The header checkbox selects or clears all rows that pass the current filters.
- `onRowSelectionChange` receives the selected ids whenever the set changes.
- `api.getSelectedRows()` returns the ticked rows themselves, in view order.

## Row ids

Selection is keyed by `row.id`. If your rows are identified by another field, such as a UUID or a composite key, pass `getRowId`:

```svelte
<Grid {rows} {columns} rowSelection getRowId={(r) => String(r.uuid)} height={480} />
```

## One active row

For a list-and-detail layout, where one row is "open", use `selectedRowId` instead. It highlights a single row, is fully controlled by your app, and is independent of the checkboxes. Pair it with `onRowClick`:

```svelte
<Grid {rows} {columns} selectedRowId={openId} onRowClick={(r) => (openId = r.id)} height={480} />
```

## With server data

With a server [data source](https://bonguynvan.github.io/bo-grid/docs/server-data/), the checkboxes work on loaded rows. The header checkbox is disabled, because ids of rows that are not loaded cannot be listed.

## Reference

- `rowSelection`: `boolean` (default `false`) — Show a leading checkbox column for whole-row selection (keyed by row id, stable across sort/filter).
- `onRowSelectionChange`: `(selectedIds: Array<string | number>) => void` — Called with the selected row ids whenever the row-selection set changes.

  ```svelte
  <Grid {rows} {columns} height={480} rowSelection onRowSelectionChange={(ids) => (selected = ids)} />
  ```

- `getRowId`: `(row: GridRow) => string | number` (default `(row) => row.id`) — Identity key for rows: selection, focus, pins and flashes follow it. Override for string/UUID/composite keys.

  ```svelte
  <Grid {rows} {columns} height={480} getRowId={(row) => `${row.account}:${row.sym}`} />
  ```

- `selectedRowId`: `string | number | null` (default `null`) — Controlled "active row" highlight (keyed by `getRowId`) — for master-detail / list-detail where one row is selected. Independent of the checkbox `rowSelection` and the cell range selection. `null` = none.
- `onRowClick`: `(row: GridRow, event: MouseEvent | KeyboardEvent) => void` — Called when a data row is activated by click or Enter (open a detail view, navigate, …). Edit-input and checkbox clicks are excluded.

  ```svelte
  <Grid {rows} {columns} height={480} {selectedRowId} onRowClick={(row) => (selectedRowId = row.id)} />
  ```


- `getSelectedRows(): GridRow[]` — Ticked rows (needs `rowSelection`), in view order.

  ```ts
  const ids = api.getSelectedRows().map((row) => row.id);
  ```

---
Page: https://bonguynvan.github.io/bo-grid/docs/row-selection/ · All pages: https://bonguynvan.github.io/bo-grid/llms.txt
