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:

FieldTypeDescription
appliedstring[]Slice names present and applied ('sort', 'columns', …)
skippedstring[]Known slices absent from the input (left untouched)
warningsstring[]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

SliceContents
columnsPer-column order, width, pinning, visibility
sortActive sort expressions (comparers omitted)
filterPer-column filters (condition captured by operand name)
quickFilterGlobal quick-filter term
pagination{ page, pageSize }
selectionSelected rows as RowRefs
expansionExpanded master-detail rows
treeExpanded / treeExpandedKeysExpanded tree rows
rowPinningPinned rows per band (top/bottom)
rowOrderManual drag-reorder order, or null
modulesPer-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} />
}