addExpandedRows
addExpandedRows expands and collapses sub-rows of rows. Sub-rows are defined by plugins such as addSubRows or addGroupBy.
Options
Information:
Options passed into
addExpandedRows.const table = createTable(data, {
expand: addExpandedRows({ ... }),
});const table = createTable(data, {
expand: addExpandedRows({ ... }),
});initialExpandedIds?: Record<string, boolean>
Initial expanded row ids as an object mapping rowId => boolean. Nested sub-rows use {parentId}>{id}.
Column Options
Information:
Options passed into column definitions.
const columns = table.createColumns([
table.column({
header: 'Name',
accessor: 'name',
plugins: {
expand: { ... },
},
}),
]);const columns = table.createColumns([
table.column({
header: 'Name',
accessor: 'name',
plugins: {
expand: { ... },
},
}),
]);Prop Set
Information:
Extensions to the view model. Read
current.props on table components.{#each vm.current.headerRows as headerRow (headerRow.id)}
{headerRow.current.props.expand}
{#each headerRow.cells as cell (cell.id)}
{cell.current.props.expand}
{/each}
{/each}{#each vm.current.headerRows as headerRow (headerRow.id)}
{headerRow.current.props.expand}
{#each headerRow.cells as cell (cell.id)}
{cell.current.props.expand}
{/each}
{/each}Interactions
- Filters (
addColumnFilters,addTableFilter) keep a sub-row when it or one of its descendants matches. Registering the filter plugin beforeexpandfilters the tree first; either order yields the same visible rows. - With
addPagination, expanded children count toward the page size, so expanding a row can push later rows onto the next page.
Plugin State
Information:
State provided by
addExpandedRows.const vm = table.createViewModel(columns)
const { pluginStates } = vm
const { expandedIds, getRowState } = pluginStates.expandconst vm = table.createViewModel(columns)
const { pluginStates } = vm
const { expandedIds, getRowState } = pluginStates.expandexpandedIds: RecordSet
The expanded row ids. Read expandedIds.current (a Record<string, boolean> holding only true entries), or change it with add(id), remove(id), toggle(id), addAll(ids), removeAll(ids) and clear(). Assigning expandedIds.current replaces the whole set.
getRowState: (row) => ExpandedRowsRowState
Returns the expansion state of a BodyRow:
isExpanded: Box<boolean>: writing adds or removes the row’s id inexpandedIdscanExpand: boolean: whether the row currently has sub-rows. Read it from the state object (getRowState(row).canExpand) when you render; a value you destructured earlier is a snapshot.isAllSubRowsExpanded: ReadonlyBox<boolean>
The state holds nothing of its own (it reads expandedIds), so it is safe to call anywhere, including in a template. The same row object always returns the same view.
Information:
v7 removed
invalidate(): there is no per-row cache to clear.<!-- ExpandIndicator.svelte, rendered with createRender(ExpandIndicator, getRowState(row)) -->
<script lang="ts">
import type { Box } from '@humanspeak/svelte-headless-table'
const { isExpanded, canExpand }: { isExpanded: Box<boolean>; canExpand: boolean } = $props()
</script>
{#if canExpand}
<button onclick={() => (isExpanded.current = !isExpanded.current)}>
{isExpanded.current ? 'Collapse' : 'Expand'}
</button>
{/if}<!-- ExpandIndicator.svelte, rendered with createRender(ExpandIndicator, getRowState(row)) -->
<script lang="ts">
import type { Box } from '@humanspeak/svelte-headless-table'
const { isExpanded, canExpand }: { isExpanded: Box<boolean>; canExpand: boolean } = $props()
</script>
{#if canExpand}
<button onclick={() => (isExpanded.current = !isExpanded.current)}>
{isExpanded.current ? 'Collapse' : 'Expand'}
</button>
{/if}Examples
Simple row expanding
| Name (10 users) | Info | |||||
|---|---|---|---|---|---|---|
| First Name | Last Name | Age | Status | Visits | Profile Progress | |
| Ricky | Mertz | 43 | complicated | 42 | 33 | |
| Roberto | Kling | 30 | single | 62 | 58 | |
| Helene | Ruecker | 53 | single | 42 | 13 | |
| Sharon | Grady | 42 | single | 43 | 67 | |
| Emerald | Ebert | 40 | relationship | 20 | 94 | |
| Anjali | Prosacco | 64 | single | 86 | 11 | |
| Dean | Reinger | 36 | complicated | 45 | 70 | |
| Myrtice | Kemmer | 41 | single | 20 | 98 | |
| Pasquale | Fay | 64 | complicated | 95 | 51 | |
| Major | Medhurst | 58 | relationship | 26 | 44 | |
Simple grouping by column
{
"groupByIds": []
} | Name (30 users) | Info | |||||
|---|---|---|---|---|---|---|
| First Name | Last Name | Age | Status | Visits | Profile Progress | |
| Janae | Lind-Kuvalis | 21 | single | 27 | 50 | |
| Arthur | Effertz | 39 | complicated | 94 | 2 | |
| Jonas | Ledner | 54 | relationship | 67 | 47 | |
| Josefina | Runte | 33 | complicated | 57 | 27 | |
| Gillian | Jerde | 61 | complicated | 18 | 74 | |
| Kaycee | Bosco | 52 | single | 52 | 70 | |
| Elliot | Wintheiser | 63 | single | 85 | 47 | |
| Jessyca | Collins | 34 | relationship | 32 | 30 | |
| Nona | Koelpin | 55 | single | 89 | 68 | |
| Sherman | Schinner | 52 | relationship | 14 | 66 | |
| Ivy | Schuster | 54 | complicated | 0 | 42 | |
| Lisa | Champlin | 29 | relationship | 66 | 13 | |
| Phillip | Lemke | 56 | relationship | 98 | 27 | |
| Claudie | Sporer | 26 | complicated | 67 | 81 | |
| Elena | Adams | 35 | relationship | 6 | 15 | |
| Guy | McLaughlin | 63 | relationship | 100 | 24 | |
| Jessie | Monahan | 59 | relationship | 2 | 27 | |
| Ali | Hessel | 38 | complicated | 18 | 52 | |
| Candida | Hodkiewicz | 27 | relationship | 92 | 83 | |
| Jazmin | Walker | 36 | single | 65 | 60 | |
| Trycia | Pacocha | 52 | single | 66 | 14 | |
| Kent | Schuppe-Nienow | 54 | relationship | 18 | 31 | |
| Sylvan | Braun | 50 | relationship | 82 | 63 | |
| Roderick | Langworth | 48 | complicated | 26 | 85 | |
| Bradly | Romaguera | 44 | relationship | 46 | 90 | |
| Allan | Trantow | 46 | relationship | 34 | 99 | |
| Gina | Hansen | 60 | relationship | 65 | 33 | |
| Jalyn | Tromp | 25 | single | 78 | 13 | |
| Trevion | Ledner | 22 | relationship | 10 | 15 | |
| Una | Carter | 28 | complicated | 77 | 94 | |