State Persistence
ApexGrid can serialize its restorable state (column layout, sort, filter, quick-filter, pagination, selection, expansion, tree, and per-module state) to a plain JSON object, and apply it back later. This powers "remember my view" features, shareable view links, and server-side view storage. Available on both <apex-grid> and <apex-grid-enterprise> since v3.3.
getState()
Returns a JSON-safe GridState snapshot:
const grid = document.querySelector('apex-grid')
const state = grid.getState()
localStorage.setItem('grid-view', JSON.stringify(state))
Functions and templates are never serialized: sort comparers, filter condition functions, and cell/header/editor templates are re-bound from the live column configuration on restore. Filter conditions are captured by operand name (e.g. 'contains').
setState()
Applies a (partial) snapshot. It never throws on malformed or stale input by default: it applies what it recognizes, skips the rest, and reports back a result.
const saved = localStorage.getItem('grid-view')
if (saved) {
const result = grid.setState(JSON.parse(saved))
console.log('applied:', result.applied) // e.g. ['columns', 'sort', 'filter']
console.log('skipped:', result.skipped)
console.log('warnings:', result.warnings) // anything dropped / clamped / unresolved
}
SetStateResult:
| Field | Type | Description |
|---|---|---|
applied | string[] | Slice names present and applied ('sort', 'columns', …) |
skipped | string[] | Known slices absent from the input (left untouched) |
warnings | string[] | Human-readable notes for anything dropped, clamped, or unresolved |
Pass { strict: true } to throw on the first problem instead of degrading — useful in tests:
grid.setState(snapshot, { strict: true })
What GridState captures
| Slice | Contents |
|---|---|
columns | Per-column order, width, pinning, visibility |
sort | Active sort expressions (comparers omitted) |
filter | Per-column filters (condition captured by operand name) |
quickFilter | Global quick-filter term |
pagination | { page, pageSize } |
selection | Selected rows as RowRefs |
expansion | Expanded master-detail rows |
treeExpanded / treeExpandedKeys | Expanded tree rows |
rowPinning | Pinned rows per band (top/bottom) |
rowOrder | Manual drag-reorder order, or null |
modules | Per-module serialized state, keyed by module id (enterprise) |
Row identity: set rowId for durable references
Rows are captured as RowRefs. With a rowId resolver each row is captured by a stable id; without one, rows are captured by positional index, which round-trips within a session but not across a data reload. For state that survives a data refresh, configure rowId:
grid.rowId = (row) => row.id
You can also override it per call: grid.getState({ rowId }) / grid.setState(state, { rowId }).
getSchema()
Returns a machine-readable description of the grid's columns and capabilities — the shape an LLM or a state-builder UI can use to construct a valid setState payload:
const schema = grid.getSchema()
Reacting to state changes
The stateChanged event fires after any restorable change (user interaction or a programmatic setState). Its payload carries the fresh snapshot, so you can autosave without polling. The event is zero-cost when no listener is attached.
grid.addEventListener('stateChanged', (e) => {
localStorage.setItem('grid-view', JSON.stringify(e.detail.state))
})
Complete save/restore example
import 'apex-grid/define'
const grid = document.querySelector('apex-grid')
grid.rowId = (row) => row.id
grid.columns = columns
grid.data = data
// restore on load
const saved = localStorage.getItem('grid-view')
if (saved) grid.setState(JSON.parse(saved))
// autosave on every change
grid.addEventListener('stateChanged', (e) => {
localStorage.setItem('grid-view', JSON.stringify(e.detail.state))
})
// reset button
document.querySelector('#reset').addEventListener('click', () => {
localStorage.removeItem('grid-view')
location.reload()
})
React example
import { useEffect, useRef } from 'react'
import 'apex-grid/define'
export default function PersistentGrid() {
const ref = useRef<any>(null)
useEffect(() => {
const grid = ref.current
if (!grid) return
grid.rowId = (row: any) => row.id
grid.columns = columns
grid.data = data
const saved = localStorage.getItem('grid-view')
if (saved) grid.setState(JSON.parse(saved))
const onChange = (e: any) =>
localStorage.setItem('grid-view', JSON.stringify(e.detail.state))
grid.addEventListener('stateChanged', onChange)
return () => grid.removeEventListener('stateChanged', onChange)
}, [])
return <apex-grid ref={ref} />
}