Column headers - styling & height
Headers are rendered as <th> inside a <thead> with role="row". Style
them with regular CSS - there are no header-specific Svelte props.
Open the live example: Quick start (Getting Started)
Set header text
{ field: 'firstName', header: 'First name' }
For computed headers, pass a function returning a renderSnippet /
renderComponent - see Custom header components.
Header height
Set a fixed height per header level with the headerHeight prop on
<SvGrid>:
<SvGrid {data} {columns} headerHeight={44} />
With multi-level (grouped) headers the total header height is
levels * headerHeight - each level renders as its own row, so a two-level
header at headerHeight={44} is 88px tall. The filter row is not affected.
When omitted, header rows size to their content (the default). You can also size headers purely with CSS instead of the prop:
table[role='grid'] thead th {
height: 40px;
padding: 0.4rem 0.6rem;
}
If you set a fixed virtualizer row height (rowHeight={36} on <SvGrid>)
the header is independent of that - the virtualizer measures the header
once at mount (and on resize) to compute the visible viewport.
Long labels (truncation)
A header label wider than its column truncates to a single line with an
ellipsis (…) instead of wrapping or pushing the header taller - so a fixed
headerHeight stays intact. This applies to plain string headers. With
custom header components you own the markup,
so apply the same rule to your label element to get the effect:
.my-header-label {
min-width: 0; /* required inside the header's flex row */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
Header colour, weight, alignment
The grid leans on the gallery's tokenised CSS:
table[role='grid'] thead tr {
background: var(--sg-header-bg);
color: var(--sg-header-fg);
}
table[role='grid'] th {
border: 1px solid var(--sg-border);
font-weight: 600;
text-align: left;
}
Set those custom properties at :root, on an ancestor, or directly on the
grid host to change the look.
Sortable header indicator
When rowSortingFeature is registered, sortable headers gain a click handler
and aria-sort is updated. SvGrid renders the asc/desc arrow itself; to
restyle, target the inner span:
table[role='grid'] th [data-sort-indicator] {
opacity: 0.6;
}
table[role='grid'] th[aria-sort] [data-sort-indicator] {
opacity: 1;
}
A header that is not a string
header takes a string or a function, so a unit, an icon or a two-line label
needs no special API. Keep it short: the header row sets the column's practical
minimum width.
<script lang="ts">
import { SvGrid, renderSnippet, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const seed: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
]
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 180 },
{ field: 'salary', width: 160,
header: () => renderSnippet(SalaryHeader, {}),
format: { type: 'currency', currency: 'USD' } },
{ field: 'age', header: 'Age', width: 90 },
]
</script>
{#snippet SalaryHeader()}
<span style="display: inline-flex; flex-direction: column; line-height: 1.15;">
<span>Salary</span>
<span style="font-size: 10px; opacity: 0.6; font-weight: 400;">USD / year</span>
</span>
{/snippet}
<SvGrid data={seed} {columns} sortable rowHeight={34} />
Grouped headers
A group is a column with columns instead of a field. Give it an explicit
id - without a field there is nothing else for the grid to key it on. The
header row count follows the deepest branch, so a grouped column next to a plain
one lines up without spacer rows.
<script lang="ts">
import { SvGrid, renderSnippet, type GridColumns, type SvGridApi } from '@svgrid/grid'
type Person = {
id: number
name: string
department: string
city: string
age: number
salary: number
}
const seed: Person[] = [
{ id: 1, name: 'Ada Lovelace', department: 'Engineering', city: 'London', age: 36, salary: 142000 },
{ id: 2, name: 'Grace Hopper', department: 'Engineering', city: 'New York', age: 45, salary: 168000 },
{ id: 3, name: 'Linus Torvalds', department: 'Platform', city: 'Portland', age: 54, salary: 155000 },
{ id: 4, name: 'Radia Perlman', department: 'Networking', city: 'Seattle', age: 49, salary: 161000 },
]
const columns: GridColumns<Person> = [
{ field: 'name', header: 'Name', width: 180 },
{
id: 'employment',
header: 'Employment',
columns: [
{ field: 'department', header: 'Department', width: 160 },
{ field: 'salary', header: 'Salary', width: 140,
format: { type: 'currency', currency: 'USD' } },
],
},
{ field: 'city', header: 'City', width: 140 },
]
</script>
<SvGrid data={seed} {columns} sortable />
See also
Related articles
- Multi-Level (Grouped) Column Headers in SvGrid - Band related columns under a shared parent header using SvGrid's nested column definition - how to nest, pin, combine with sorting and filtering, and when NOT to use grouping.
- A Density (Row-Height) Toggle for SvGrid - Let users pick compact, comfortable, or spacious rows - wired through CSS tokens, synced with the virtualizer, and persisted across sessions.
- A Custom Column Header Menu in SvGrid - Build a per-column header menu for sort, hide, pin, and custom actions using header snippets and your own dropdown component.