JavaScript Data Grid Events API
Every notable thing the grid does is announced as an event, so your application can follow a selection, an edit, a sort or a filter without polling for it. The before-events go further: they hand you the action while it can still be stopped, so a rule of yours can refuse it and give the reason.
Developer guide › JavaScript Data Grid Events API
Events
One bus, 111 events. The table below is the working set, the ones most applications
actually reach for; a complete index by area follows it, and the
reference lists them all.
| Event | Carries | Use it for |
| ready | {} | First render is done. Fires on a future turn, so you can subscribe on the line after createGrid. |
| cell:changed | { row, key, colId, value, oldValue, undo } | Persisting an edit. undo distinguishes a rollback from a fresh change. |
| selection:changed | { keys } | Enabling a bulk action. |
| range:changed | { ranges } | A status bar showing the sum of what is selected: see selection.summary(). |
| sort:changed / filter:changed | { sort } / { filters } | Reflecting the view in the URL. |
| history:changed | { canUndo, canRedo, undo, redo } | Driving your own undo button. Emitted after the entry is pushed, so the label is right. |
| history:applied | { direction, step } | An action was undone or redone, with which and what. history:changed also fires when a new action is pushed, so it cannot distinguish the two. |
| form:saved | { key, values, changed, unmapped } | Persisting a row edited on a form. unmapped names the fields that are not columns, which the grid reports rather than writes. |
| form:error | { key, error, timedOut } | A row form's load failed or ran out of time. The panel stays open with a retry. |
| view:saved / :removed | { view, views } | Persisting saved views to a server. |
| render:done | { first, last } | Decorating cells from outside. The cell layer rewrites class names on every paint, so anything added before this is erased. |
Every event, by area
The table above is the working set. This is the whole list, grouped by what it is about,
so a question like "can I hear about a column being pinned?" is answerable by scanning
rather than by reading the reference end to end.
Lifecycle
| Event | Fires when |
| config:changed | A configuration key changed. Emitted after the grid has rebuilt, so a listener reading the grid back sees the change rather than what it replaced. |
| destroy | grid.destroy() has run. |
| licence:changed | A key was installed, and again when verification settles. |
| ready | First layout is complete and the API is safe to drive. |
| render:done | The cells are written and stable. Anything decorating them from outside must run after this, the cell layer rewrites each cell's className wholesale and would otherwise erase it. |
| render:first | First paint, the number to measure time-to-first-row against. |
Data
| Event | Fires when |
| model:changed | Columns, grouping, pivot or another structural change. |
| row:clicked | Emitted alongside the cell event, cell first. |
| row:copied | A row was duplicated. |
| row:dblclicked | A row was double-clicked. Emitted alongside the cell event, cell first. |
| row:edit:end | In row mode an invalid cell blocks the whole commit and the session stays open. |
| row:edit:start | Replaces the cell pair when edit.mode is 'row'. |
| row:moved | A row was dragged to a new position. |
| row:received | A row arrived from a source. |
| row:sent | A row was written back to a source. |
| rowDrag:started | A row drag began. Fires on the grid the drag started in, as do rowDrag:moved, rowDrag:left and rowDrag:ended. |
| rowDrag:moved | The drag is over a candidate position. Coalesced to one event per animation frame, carrying that frame's latest pointer position. |
| rowDrag:left | The pointer left a grid; over names the grid it left. Emitted on the transition, not on a frame. |
| rowDrag:ended | The gesture ended, whether or not a drop followed, including a release outside every grid. dropped says whether the release is being acted on. Notifications only - none of the four is cancellable. |
| rows:changed | The row set changed. See what a change firing promises: identified means the three arrays name the rows that moved, companion marks a duplicate announcement of a change already made with identity, and a firing with neither is a real change of unknown extent. |
| rows:deferred | Updates were held rather than applied, because an edit is in flight. |
| rows:paused | A live feed was paused; updates queue from here. |
| rows:queued | A batched change is waiting for the next frame. |
| rows:resumed | The feed resumed and the queue drained. |
| source:error | A source or block load failed. |
| stream:chunk | A streamed chunk landed. |
| stream:end | Streaming finished; promoted means it switched to in-memory. |
| stream:evicted | A streaming source dropped rows to stay within its cap. |
Cells and editing
| Event | Fires when |
| cell:changed | A committed edit reached the data. undo distinguishes a rollback. |
| cell:clicked | A cell was clicked. Announcement only: nothing is consumed, so editing and selection behave unchanged. |
| cell:confirmed | The write reached the server. |
| cell:conflict | The write was accepted but the server row had moved underneath it. Last-write-wins with the divergence surfaced: your value stands and serverRow carries the server's truth. |
| cell:contextmenu | Right-click on a cell. |
| cell:dblclicked | A cell was double-clicked. Carries the row, column, value and text. |
| cell:mouseover | The pointer entered a cell. Fires once per cell, carries what cell:clicked carries plus the cell element as target, and is delegated on the viewport so it stays correct over pooled rows. |
| cell:mouseout | The pointer left a cell. Fires once per cell, including when the pointer left the grid; moving to the next cell fires this first, then cell:mouseover. |
| cell:mousedown | A pointer button went down on a cell. Carries what cell:clicked carries plus the cell element as target, and is delegated on the viewport so it stays correct over pooled rows. |
| cell:mouseup | A pointer button was released over a cell. Same shape as cell:mousedown. |
| cell:edit:end | It closed: committed or cancelled. |
| cell:edit:start | An edit session opened. |
| cell:pending | Applied optimistically, not yet durable. Only with edit.commit. |
| cell:reverted | The write failed. applied: false means a newer edit owned the cell, so nothing was written back. |
| row:pending | A row was appended or deleted optimistically, not yet durable. kind is 'append' or 'delete'. Only over a source that declares mutate.append/delete. |
| row:confirmed | The append or delete reached the server. An appended row has already been rekeyed from its temp key to the server key, and selection, expansion, focus and in-flight cell edits followed. |
| row:reverted | The append or delete failed: an appended row is removed, a deleted row restored. applied: false means a newer op owned the key, so nothing was undone. |
| row:conflict | The op succeeded but the server row had moved underneath it. Last-write-wins with the divergence surfaced: serverRow carries the server's truth. |
| form:closed | The row form closed without saving. |
| form:error | A commit from the form failed validation or was rejected. |
| form:opened | The row form opened. |
| form:saved | The row form committed. |
Columns
| Event | Fires when |
| column:filter:open | Header filter popup opened. |
| column:profile:open | The column statistics ("describe") panel was asked to open on a column, from the column menu's "Column statistics" item ({ colId }). A mounted tool panel opens its statistics panel seeded on that column. |
| column:grouped | The row-group column list changed. |
| column:menu:open | Header menu opened. |
| column:moved | Reordered by drag or by API. |
| column:pinned | side is 'start', 'end' or null. |
| column:pivoted | The pivot configuration changed. |
| column:resized | A column width settled after a drag or a keyboard resize. |
| column:visible | Columns shown or hidden. |
| columns:changed | The column set was replaced or reordered wholesale. |
| columns:tagged | A column's tags changed. |
Query and view
| Event | Fires when |
| facet:computed | A header histogram finished counting. Carries the column and the buckets. |
| facet:expanded | The facet band was opened or collapsed. |
| facet:failed | A distribution could not be computed. Carries the reason. |
| facet:filtered | A bucket or a dragged range was applied as a filter. |
| filter:changed | The condition tree or the quick filter changed. |
| page:changed | Fired after the rows have moved, whether the page changed by API or by the pager control. |
| sort:changed | The full sort entry list. |
| state:changed | Every state change, whether a user gesture or a programmatic call - including a named filters.where predicate registered, replaced, removed or reapplied - announced exactly once. cause is 'user', 'apply' or 'reset'; sections names the GridState keys that moved; report lists anything a restore could not apply. A save layer subscribes to this one event and ignores cause 'reset'. |
| state:reset | The grid was returned to its baseline. |
| timeline:attached | A time brush was connected to the grid. |
| timeline:detached | The brush was removed. |
| timeline:seek | The brush settled on a range. |
| timeline:seeking | The brush is being dragged. Throttled. |
| annotation:changed | A drawing annotation was added, edited or cleared. Carries the active tool and the mark count. Declared so grid.on('annotation:changed', ...) and the adapters' onAnnotationChanged reach it directly instead of via the '*' wildcard. |
| view:applied | Emits no storage write: applying a view changes nothing to persist. |
| view:default | view is null when the default was cleared. |
| view:removed | A saved view was deleted. |
| view:renamed | A saved view was renamed. |
| view:saved | Carries the one view that moved: enough to POST a single record without diffing two lists. |
Selection and interaction
| Event | Fires when |
| detail:toggled | A master-detail row opened or closed. |
| group:toggled | A group row opened or closed. |
| history:applied | An action was undone or redone. Distinct from history:changed, which also fires when a new action is pushed onto the stacks and so cannot tell you anything was reversed. |
| history:changed | Emitted after the entry is pushed, so a toolbar reading it names the right action. Repainting from sort:changed instead reads the timeline one action behind. |
| range:changed | Cell range selection changed. |
| scroll | Throttled to the frame. |
| scroll:end | Scrolling settled, the moment to trigger deferred work. |
| selection:changed | The selected rows changed. Carries the keys. |
| size:changed | The viewport resized. |
Cancellable before-events
Every user-initiated mutation has a paired cancellable before event. The handler
receives a BeforeEvent carrying the action context plus preventDefault(reason?),
defaultPrevented and reason. Calling preventDefault() - or
returning false, the legacy kanban onBeforeMove idiom - cancels the action.
A handler may be async; the mutation is held until every registered before-handler
settles, so a confirm dialog or a server check genuinely gates the write. Any one handler
preventing cancels it (veto wins), and a handler that throws is treated as a cancel and surfaced.
On a veto the paired <action>:cancelled event fires carrying the reason.
These fire for user actions only. Host/API writes (for example
grid.edit.setCells) and remote/router-applied deltas (rows.apply,
origin !== 'user') do not fire them - remote truth is not a user gesture and
does not self-veto. The origin field carried on each before-event lets a host
deduplicate a module-initiated write (a kanban or Gantt move that re-enters core) from a genuine
user gesture. If a handler was async and the underlying state moved during the await
(a row removed, a value changed by a live delta), the gate re-validates and cancels with reason
'stale' rather than applying against state that has moved. With no before-handler
registered every mutation stays synchronous and behaves exactly as before.
| Event | Fires when |
| beforeEdit | Before a validated cell/row commit applies. Carries row, key, mode, changes, origin. Validation (edit.validate) is separate and runs first. Paired with edit:cancelled. |
| beforeSort | Before a sort is set. Paired with sort:cancelled. |
| beforeFilter | Before a structured or quick filter is set (kind tells them apart). Paired with filter:cancelled. |
| beforeColumnMove | Before a column reorder applies, earlier than the post-mutation column change. Paired with columnMove:cancelled. |
| beforeColumnResize | Before a column width change applies. Paired with columnResize:cancelled. |
| beforeColumnHide | Before one or more columns are hidden. Paired with columnHide:cancelled. |
| beforeSelect | Before a user selection change applies; a veto snaps back to the last announced selection. Paired with selection:cancelled. |
| beforeRowAdd | Before an optimistic row append applies. Paired with rowAdd:cancelled. |
| beforeDelete | Before an optimistic row delete applies - the canonical confirm-before-delete hook. Paired with delete:cancelled. |
| beforeRowMove | Before a row reorder applies. Paired with rowMove:cancelled. |
| beforeGroup | Before a group/tree expand or collapse applies. Paired with group:cancelled. |
| beforeRowReceive | Before a row dragged from another grid is inserted into this one; fires on the receiving grid and names the row under the pointer (overKey). A veto leaves the source grid untouched. Paired with rowReceive:cancelled. |
| edit:cancelled | A beforeEdit was vetoed; reason is 'stale' when a live delta moved the cell during an async gate. |
| sort:cancelled | A beforeSort was vetoed. |
| filter:cancelled | A beforeFilter was vetoed. |
| columnMove:cancelled | A beforeColumnMove was vetoed. |
| columnResize:cancelled | A beforeColumnResize was vetoed. |
| columnHide:cancelled | A beforeColumnHide was vetoed. |
| selection:cancelled | A beforeSelect was vetoed; the selection snapped back. |
| rowAdd:cancelled | A beforeRowAdd was vetoed. |
| delete:cancelled | A beforeDelete was vetoed; reason is 'stale' when the row was already gone. |
| rowMove:cancelled | A beforeRowMove was vetoed; reason is 'stale' when the row had moved. |
| group:cancelled | A beforeGroup was vetoed. |
| rowReceive:cancelled | A beforeRowReceive was vetoed; nothing was inserted and the source still holds the row. reason is 'stale' when the row under the pointer or the source row was gone by the time an async handler settled. |
| export:request | A remote export was requested. Past-tense notification. |
| export:done | A remote export completed. Past-tense notification. |
| shortcuts:opened | The keyboard-shortcuts help overlay opened. Past-tense notification. |
| shortcuts:closed | The keyboard-shortcuts help overlay closed. Past-tense notification. |
| print:before | Print mode is about to snapshot. Past-tense notification, not cancellable. |
| print:after | Print mode restored the grid, even if the browser cancelled the print. |
Presentation and formatting
| Event | Fires when |
| formatting:changed | A conditional formatting rule was added, edited, reordered or restated. |
| highlight:changed | A highlight was added or cleared. |
| find:changed | The find query, its matches, the current match or the bar's open state changed; carries the FindCount, partial while the sliced scan runs. |
| permissions:changed | The context moved and every column re-resolved. |
| presentation:captured | A PNG was taken. |
| presentation:changed | The options of a running presentation changed. |
| presentation:ended | Presentation mode ended. Annotations are cleared here. |
| presentation:scale | The presentation zoom changed. |
| presentation:spotlight | A region was spotlit or released. |
| presentation:started | Presentation mode began. Carries the scale, options, views and starting index. presentation:changed covers a later change to the same options, so a listener can tell entry from adjustment. |
| presentation:view | The presentation advanced to another saved view. |
| redaction:changed | A column was redacted or restored. |
Collaboration
| Event | Fires when |
| comment:added | A comment was posted. |
| comment:deleted | A comment was removed. |
| comment:edited | A comment was changed. |
| comment:failed | A comment could not be saved. Carries the reason. |
| comment:indexLoaded | The comment index finished loading, so indicators can paint. |
| comment:resolved | A thread was marked resolved. Carries the cellKey. |
| comment:threadClosed | A thread was closed or resolved. |
| comment:threadOpened | A thread was opened in the panel. |
| comment:unresolved | A resolved thread was reopened. Carries the cellKey. |
| presence:failed | A presence transport error. Presence is lossy by design; this is informational. |
| presence:joined | A peer was seen for the first time. Carries the peer. |
| presence:left | A peer disconnected. |
| presence:lockRefused | An edit was refused because a peer holds the cell. |
| presence:published | This client's cursor or selection was broadcast. |
| presence:updated | A known peer moved or changed selection. Carries the peer. |
Everything else
| Event | Fires when |
| clipboard:copy | A copy left the grid. |
| diff:changed | A snapshot was set or cleared. |
| diff:swapped | The baseline and the current rows were exchanged. |
| export:progress | Progress on a streamed export. |
| header:contextmenu | A column heading was right-clicked. |
| toolpanel:focus | The documented keyboard shortcut reached the tool panel. |
| tree:loadAborted | A child fetch was cancelled, usually because the node collapsed. |
| tree:loadFailed | A child fetch failed. |
| tree:loaded | Children arrived. Carries the key and the count. |
| tree:loading | Children are being fetched for a node. |
| views:changed | The whole list, plus what moved and why. |