Skip to main content
Urbicon UI

Row Selection

Checkbox selection for one row or many, with a select-all across every filtered page. The table owns the selected set until you pass selectedIds.

Selection Modes

selectionMode switches on a checkbox column. "multi" lets the user mark any number of rows and adds a select-all checkbox to the header. "single" keeps one row at a time: selecting a row clears the one before. The default, "none", is the table without a checkbox column.

Select-all covers every row that matches the current search and filters, on every page, not just the rows on screen. While only part of that set is selected, the checkbox shows as indeterminate.

The selection is a set of ids, keyed by item.id, or by the row's position in the items array you passed when a row has none. Sorting, paging and filtering change what is on screen, not the set: a selected row that moves to another page stays selected. onSelectionChange reports each change, with the selected rows and their ids; paging or sorting is not a change and does not fire it.

Live — select-all spans both pages

Name
Role
Department
Location
Emma Wilson
Staff Engineer
Platform
Berlin
Liam Chen
Product Designer
Design
Hamburg
Sofia Martinez
Engineering Manager
Platform
Munich
James Park
Frontend Developer
Product
Remote

0 selected

<script lang="ts">
  let selected = $state<Employee[]>([]);
</script>

<Table
  {items}
  {columns}
  selectionMode="multi"
  viewDefaults={{ pageSize: 4 }}
  onSelectionChange={(items) => (selected = items)}
/>

<p>{selected.length} selected</p>

Selecting by Row Click

In "single" mode a click anywhere on the row selects it: the checkbox is not the only target. In "multi" mode, and wherever onRowClick or expandable rows already give a click another meaning, only the checkbox selects. rowClickSelects decides it explicitly in either mode.

Single select — click the row

Name
Role
Department
Location
Emma Wilson
Staff Engineer
Platform
Berlin
Liam Chen
Product Designer
Design
Hamburg
Sofia Martinez
Engineering Manager
Platform
Munich
James Park
Frontend Developer
Product
Remote
<Table
  {items}
  {columns}
  selectionMode="single"
  onSelectionChange={(items) => handleSelect(items[0])}
/>

A row you only show somewhere else, the master/detail pattern, is not a selection. activeRowId highlights the row your onRowClick handler opened, without bringing the checkbox column along.

Controlled Selection

The table owns the selection until you pass selectedIds, from then on your code does. Take it over when the set has a life outside the table: preselected from the URL, cleared after a bulk action, shared with another view. If all you need is a starting value, initialSelectedIds={[1, 3]} seeds the table-owned selection once. Later changes to that prop are ignored, and it is ignored altogether when selectedIds is set.

Every value you pass in selectedIds becomes the table's selection, and clicks keep arriving through onSelectionChange, which hands you the selected rows and their ids. Write the ids back: they are always the whole selection, while the rows can only be the ones the table currently holds — under server processing that is one page, so mapping the rows would drop everything selected on another page. An empty array is a valid value (nothing selected); undefined hands the selection back to the table. Your own writes fire onSelectionChange as well, and writing the same ids back is a no-op, so the Clear button below settles rather than looping. A controlled selection is never written to storage: persistSelection in the preference channel restores only a table-owned one.

Controlled — buttons and checkboxes write the same set

2 selected
Name
Role
Department
Location
Emma Wilson
Staff Engineer
Platform
Berlin
Liam Chen
Product Designer
Design
Hamburg
Sofia Martinez
Engineering Manager
Platform
Munich
James Park
Frontend Developer
Product
Remote
Aisha Patel
Data Scientist
Data
Berlin
Noah Kim
DevOps Engineer
Platform
Hamburg
<script lang="ts">
  let selectedIds = $state<Array<string | number>>([1, 3]);
</script>

<Table
  {items}
  {columns}
  selectionMode="multi"
  {selectedIds}
  onSelectionChange={(items, ids) => (selectedIds = ids)}
/>

<Button onclick={() => (selectedIds = [])}>Clear selection</Button>

Write every change back

When onSelectionChange does not feed selectedIds, clicks still change the screen and nothing warns; the next change to the prop then throws the user's clicks away.