Row Pinning
A pinned row leaves the flow and sticks to the top or the bottom of the viewport. It is taken from the source rows, before filtering and sorting, so it stays put while everything else moves under it.
Basic Usage
Suspended members start pinned to the top. Sort by Salary or type in the quick filter and they stay where they are, because the pin split happens before the row ever reaches those stages.
import { createDataGrid, rowPinning } from '@sv5ui/datagrid';
const grid = createDataGrid<Person>({
data: people,
columns,
getRowId,
features: [
filtering(),
sorting(),
rowPinning({
// The starting side for a row, or null to leave it in the flow.
isRowPinned: (person) => (person.status === 'suspended' ? 'top' : null)
})
]
});
// A pinned row leaves the flow: it is taken from the source rows, so
// filtering and sorting never see it and it stays put while the middle
// section moves.Pinning From Code
An override set by pinRow wins over the predicate, so a row the predicate pinned can be released, and one it left alone
can be pinned. The grid below starts with the suspended rows pinned to the top by a predicate.
import { getRowPinning } from '@sv5ui/datagrid';
const pinning = getRowPinning(grid);
pinning?.pinRow('3', 'top');
pinning?.pinRow('3', 'bottom');
pinning?.pinRow('3', null); // back into the flow
pinning?.topNodes; // RowNode[] pinned to the top
pinning?.bottomNodes;
pinning?.pinnedCount;
pinning?.sideOf(node); // 'top' | 'bottom' | null
pinning?.getPinnedRows(); // { top: TRow[], bottom: TRow[] }
// Also on the flat api
grid.api.pinRow?.('3', 'top');
grid.events.on('rowPinnedChanged', ({ id, side }) => save(id, side));The Context Menu
Right-click any row below. The grid has no predicate, so every row offers Pin row top and Pin row bottom, and a pinned row offers to unpin instead. The items come from the feature, not from the
menu: DataGrid wires it for you, and Grid.ContextMenu carries them when you compose the chrome by hand.
<!-- The feature contributes its own context-menu items: Pin row top,
Pin row bottom, and Unpin row on a row that is already pinned.
DataGrid wires the context menu for you; compose it by hand and it is
Grid.ContextMenu that carries them. -->
<Grid.Root {grid}>
<Grid.ContextMenu>
<Grid.Viewport>
<Grid.Header />
<Grid.Body />
</Grid.Viewport>
</Grid.ContextMenu>
</Grid.Root>Full-Width Rows
A row whose node carries meta.fullWidth is drawn as one cell across every column, through the fullWidthRow snippet. That is how a group
header or a detail panel is rendered, and such a row is never editable and never selectable.
<script lang="ts">
import { PIPELINE_ORDER, type GridFeature } from '@sv5ui/datagrid';
// meta belongs to the pipeline, so a stage is what sets it. Six lines is
// a whole feature: this one flags the rows the snippet draws across.
const groupRowFeature = (): GridFeature<Row> => ({
id: 'group-rows',
pipelineStage: {
order: PIPELINE_ORDER.flatten,
transform: (nodes) =>
nodes.map((node) =>
node.row.fullWidth ? { ...node, meta: { ...node.meta, fullWidth: true } } : node
)
}
});
const grid = createDataGrid<Row>({
data: rows,
columns,
getRowId,
features: [groupRowFeature()]
});
</script>
{#snippet groupHeader({ row })}
<span class="font-medium">{row.team} team</span>
{/snippet}
<DataGrid {grid} fullWidthRow={groupHeader} />rowPinning() Options
| Option | Default |
|---|---|
isRowPinned | - |
Row Pinning State
What getRowPinning(grid) exposes. pinRow and getPinnedRows are also on grid.api.
| Member | Description |
|---|---|
pinRow(id, side) | Pins a row to an edge, or returns it to the flow with null |
topNodes / bottomNodes | The pinned rows |
pinnedCount | How many rows are pinned in total |
sideOf(node) | Where one row sits, override first, predicate second |
getPinnedRows() | The rows themselves rather than the nodes |
pinnedOverrides | What pinRow has set, which is what a snapshot would carry |