TypeScript with the custom element
The element is plain JavaScript at the boundary, so TypeScript needs to be told it exists. Two declarations get completion and checking back.
Plain TypeScript
The primitives worth declaring first - they are the ones you set most.
Open the live example: Sort, filter, paginate (Filtering & Search)
Add the element to HTMLElementTagNameMap, so getElementById and
querySelector return something typed:
Row must extend RowData (Record<string, unknown>), because that is the
constraint ColumnDef and SvGridApi carry:
// svgrid-elements.d.ts
import type { ColumnDef, RowData, SvGridApi } from '@svgrid/grid'
interface SvGridElement<Row extends RowData = RowData> extends HTMLElement {
data: readonly Row[]
columns: ColumnDef<never, Row>[]
api: SvGridApi<never, Row>
// A few of the 72 primitives; add the ones you use.
sortable: boolean
filterable: boolean
pageable: boolean
pageSize: number
showRowNumbers: boolean
groupBy: readonly string[]
}
declare global {
interface HTMLElementTagNameMap {
'sv-grid': SvGridElement
'sv-grid-shadow': SvGridElement
}
}
// With that in scope, both of these are checked:
const grid = document.querySelector('sv-grid')!
grid.columns = [{ field: 'name', header: 'Name' }]
grid.api.exportCsv()
The full property list is in the reference, which is generated
from the grid's own Props type - copy the rows you need rather than trying to
mirror all 98.
JSX (React, Solid, Preact)
JSX needs the tag registered separately, because intrinsic elements are a different map:
declare module 'react' {
namespace JSX {
interface IntrinsicElements {
'sv-grid': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> & {
sortable?: boolean
filterable?: boolean
'page-size'?: number
}
'sv-grid-shadow': React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>
}
}
}
Attributes in JSX are strings, so only the primitives belong here. Arrays and objects go through a ref - see React.
Typed events
cellvaluechange fires here; the map below types its detail.
Open the live example: Inline editing (Editing)
CustomEvent.detail is any by default. Declare the map once:
interface SvGridEventMap {
cellvaluechange: CustomEvent<{
rowIndex: number
columnId: string
oldValue: unknown
newValue: unknown
}>
sortingchange: CustomEvent<Array<{ id: string; desc: boolean }>>
rowselectionchange: CustomEvent<{ selection: Record<string, boolean>; rows: unknown[] }>
// `rowclick` carries the ROW, not the click event - see the reference.
rowclick: CustomEvent<Record<string, unknown>>
}
declare global {
interface HTMLElementEventMap extends SvGridEventMap {}
}
// `HTMLElement`, so addEventListener resolves against HTMLElementEventMap.
// (`querySelector('sv-grid')` gives you an `Element` unless you also add the
// HTMLElementTagNameMap declaration above.)
const el: HTMLElement = document.createElement('sv-grid')
el.addEventListener('cellvaluechange', (e) => {
e.detail.newValue // typed
})
Every event's detail shape is listed in the reference; it is
the corresponding callback's argument, verbatim, with two documented exceptions
kept for backwards compatibility.
Why these are not shipped
A .d.ts in the package would have to be generated from the same source as the
element, and kept correct across a version skew between @svgrid/grid-wc and
whatever @svgrid/grid types a consumer has installed. Hand-copying the few
props you use is more honest than a declaration file that can silently disagree
with the element you loaded.
See also
<sv-grid>reference- React - where the typing matters most.
Live examples
- Sort, filter, paginate - Three most-asked-for features wired together against ~5k rows.
- Inline editing - Typed editors (text/number/checkbox/date) with dirty tracking + save.
Related articles
- Web Components - Write Once, Use in React, Vue, and Angular - How to wrap SvGrid as a custom element, wire it across React, Vue, and Angular, and avoid the three interop traps that bite every team the first time.
- Progress and Percentage Bar Cells in SvGrid - Build in-cell progress bars in your Svelte 5 data grid - with color thresholds, accessible markup, and sorting that still works.
- 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.