Sticky Groups
Scroll deep into a long group and the row that names it is gone. stickyGroups keeps it pinned under the header, so the question "which group am I in" stops needing a scroll
back up to answer.
stickyGroups is new. It is an option of createDataGrid, needs virtualization(), and works over grouping(), tree() and pivot() alike.Basic Usage
It is an option of the grid, and it needs virtualization() beside whatever builds the groups. Scroll the grid below: each team's row stays under the header until the next team takes its place. Switch it off and scroll again to see what it was doing.
<script lang="ts">
import { createDataGrid, DataGrid, grouping, virtualization } from '@sv5ui/datagrid';
const grid = createDataGrid<Person>({
columns,
data: people,
getRowId,
// An option of the grid, not of grouping(): it works for anything
// that gives rows a level.
stickyGroups: true,
features: [
// Required. Virtualization is what knows where a row sits against
// the scroll, so without it nothing can say which rows have gone
// above the fold, and nothing sticks.
virtualization<Person>({ rowHeight: 40 }),
grouping<Person>({ by: ['team'], expandedByDefault: true })
]
});
// State on the grid, so it can be switched later.
grid.stickyGroups = false;
</script>
<!-- A virtual grid needs a height to scroll inside. -->
<DataGrid {grid} class="h-96" /><DataGrid> shorthand has no such prop, since it registers nothing that groups rows. Build the grid
with createDataGrid. Nested Groups
Each level gets a line, outermost first. Scroll into the designers of one team and both the team and the role are on screen, so a reader knows where they are in the whole tree and not only in the nearest branch.
createDataGrid<Person>({
columns,
data: people,
getRowId,
stickyGroups: true,
features: [
virtualization<Person>({ rowHeight: 40 }),
// Two levels, so two lines stick: the team, then the role inside it.
grouping<Person>({ by: ['team', 'role'], expandedByDefault: true })
]
});The stack is as deep as the grouping, and it is taken out of the viewport. A grid grouped six deep spends six rows of its height on it. This is something to turn on for shallow groups over long data, not for every grid.
On a Tree
There is no grouping in the grid below, only tree(). What sticks is the parent rows, because the mechanism follows the level a row sits at rather than any one feature. The grid finds the first row still below the top edge and walks back up through rows of ever shallower level, which is exactly the chain of ancestors of the place being read.
createDataGrid<Unit>({
columns,
data: units,
getRowId: (unit) => unit.id,
stickyGroups: true,
features: [
virtualization<Unit>({ rowHeight: 40 }),
// No grouping here. What sticks is the parent row, because the
// mechanism follows a row's level rather than any one feature.
tree<Unit>({ getParentId: (unit) => unit.parent, defaultExpandedDepth: 99 })
]
});The same is true of a pivot, whose rows are groups. A flat grid has no levels, so there the option does nothing.
With Pinned Rows
A row pinned to the top with rowPinning() is sticky as well. The two do not fight: the pinned row sits under the header and the group line sits under the pinned row. Both offsets are added up from the heights the header really draws with, so a header height of your own does not push either out of place.
createDataGrid<Person>({
columns,
data: people,
getRowId,
stickyGroups: true,
features: [
virtualization<Person>({ rowHeight: 40 }),
rowPinning<Person>({ isRowPinned: (person) => (person.id === 1 ? 'top' : null) }),
grouping<Person>({ by: ['team'], expandedByDefault: true })
]
});
// Both bands are sticky. The pinned row sits under the header, and the
// group line sits under the pinned row.A Signpost, Not a Second Set of Controls
The pinned lines are copies of rows that exist further up, so they are kept out of the way of
everything except the eye. The band is inert and hidden from assistive technology. It adds no tab stop, nothing in it can be clicked or
focused, and a screen reader hears each group once, from the row itself. To fold a group, a
reader scrolls back to its row.
Only a row that leads a group can stick. A group footer sits at the same level as the rows it closes and is never taken for their ancestor, and a detail panel is a leaf, so scrolling through a long one pins nothing.
Option
| Option | Description |
|---|---|
stickyGroups | On createDataGrid, and readable and settable as grid.stickyGroups. Keeps the group rows a reader is inside pinned under the header, one line per level |
Slots
Both go through ui, like every other slot on Theming.
| Slot | What it styles |
|---|---|
stickyGroupRows | The band holding the pinned lines, under the header |
stickyGroupRow | One pinned line |