Alerts - Enterprise

Alert rules let your users say "tell me when the data does X" - and then act on it automatically: raise a toast, tint the row, flash the cell, block the edit, or just log it. Rules are authored at runtime in a no-code builder, persisted, and shareable as JSON. No redeploy to add an alert.

Alerts ship in the paid @svgrid/enterprise package. They build on the grid's own engines: predicates reuse the same operators as the filter row (applyExcelFilter), styling paints through the conditional-format pipeline, and notifications go through the grid's toast store.

Open the live example: Alert Rules engine (Alerts)

Setup

Mount <SvGridAlerts> next to your grid and spread its formats output into the grid's conditionalFormats. The overlay watches your data reactively, runs the rule engine on every change, and paints matches back through the grid. It diffs snapshots of the data rather than listening to a single edit event, so it reacts to streaming feeds and programmatic updates as well as in-grid edits (the grid's own onCellValueChange callback covers only the latter).

Evaluation never runs inside the grid's render frame: a data change schedules one pass on the next animation frame (post-paint), so the grid always paints first. On very large or fast-moving datasets, drive it in push mode so each pass costs only the rows that actually changed.

<script lang="ts">
  import { SvGrid } from '@svgrid/grid'
  import type { ConditionalFormat } from '@svgrid/grid/format'
  import { SvGridAlerts, enableAlerts, setLicenseKey, type ExprColumn } from '@svgrid/enterprise'

  setLicenseKey('YOUR-KEY')
  enableAlerts()

  let rows = $state.raw(data)
  let alertFormats = $state<ConditionalFormat<Row>[]>([])

  // Columns the rule/expression editors offer.
  const exprColumns: ExprColumn[] = [
    { id: 'price', name: 'Price', type: 'number' },
    { id: 'region', name: 'Region', type: 'text' },
  ]
</script>

<SvGridAlerts
  data={rows}
  columns={exprColumns}
  getRowId={(r) => r.id}
  storageKey="app:alerts"
  bind:formats={alertFormats} />

<SvGrid data={rows} {columns} getRowId={(r) => r.id}
        conditionalFormats={alertFormats} />

<SvGridAlerts> renders a small control group: a bell (opens the fired-alert log) and an Alerts button (opens the rule manager). Set controls={false} to hide them and drive the panels yourself with bind:panelOpen / bind:managerOpen.

The rule model

An AlertRule has four moving parts:

Part What it is
predicate A boolean expression - when it holds, the rule matches.
trigger When the rule is checked (see below).
scope row, cell, or aggregate.
actions What happens when it fires.

Triggers

Actions

Kind Effect
toast A toast in the rule's severity colour.
highlight Tints matching rows/cells (persists while they match).
badge Colours the targeted cells.
cellFlash A brief flash on the cell that fired.
preventEdit Vetoes the edit (validation trigger).
log Records the firing in the alert log only.

Every firing is recorded in the log regardless of action, so the bell badge and the alerts panel always reflect activity.

Messages are templates: {value}, {column}, {rule}, {severity}, and {field} / {row.field} for any row field.

const rule: AlertRule = {
  id: 'price-spike',
  name: 'Price over 700',
  enabled: true,
  severity: 'warning',
  scope: 'row',
  predicate: { kind: 'cmp', column: 'price', op: 'greaterThan', value: 700 },
  trigger: { type: 'dataChange' },
  actions: [
    { kind: 'toast', message: '{name} crossed 700 -> {value}' },
    { kind: 'highlight', style: { background: '#fef3c7', color: '#92400e' } },
  ],
  createdAt: Date.now(),
}

Seed rules with the rules prop (used only when storage is empty), or let users build them in the manager.

Persistence and sharing

Pass storageKey to persist rules in localStorage; omit it for in-memory rules. The manager's Export / Import buttons round-trip the whole rule set as JSON, so a team lead can hand a set of alerts to colleagues. Under the hood this is the same pluggable-storage shape as saved views:

import { createAlertRules, localStorageAlertRules } from '@svgrid/enterprise'

const rules = createAlertRules(localStorageAlertRules('app:alerts'))
rules.save(rule)
const json = rules.export()   // share
rules.import(json)            // load

Headless usage

Not on Svelte, or want to run the engine yourself? attachAlertEngine observes a data source and routes fired events to their side effects, returning the conditional formats + flash targets to apply:

import { attachAlertEngine, localStorageAlertRules } from '@svgrid/enterprise'

// Pass your row type: without it TData defaults to Record<string, unknown>
// and `r.id` comes back as `unknown`.
const attach = attachAlertEngine<Row>({
  rules,
  getRowId: (r) => r.id,
  getData: () => currentRows,
  applyFormats: (formats) => setGridFormats(formats),
})
// later
attach.detach()

The pure createAlertEngine (no DOM, no timers) is exported too if you want full control over evaluation.

Performance and large / live datasets

Alerts are built to stay out of the grid's way. Two things make that true:

Watch mode (default)

By default the overlay reactively scans data when it changes, diffing the new array against the previous one to find the changed rows. Because Svelte replaces changed rows immutably (unchanged rows keep their reference), the diff evaluates only the rows that moved. This is the zero-config path and is fine for most grids.

Push mode (streaming / 100k+ rows)

When your app already knows which rows changed - a streaming feed, a transaction, a tick loop - hand that set straight to the overlay and skip the scan entirely. Set watch={false}, capture the handle with onReady (or bind:this), and call pushChanged with just the changed rows. Cost is then O(rows that changed), independent of total row count.

<script lang="ts">
  let rows = $state.raw(data)
  let alerts: { pushChanged: (rows: readonly Row[]) => void } | null = null

  function onTick(changed: Row[]) {
    rows = applyChanges(rows, changed) // your immutable update
    alerts?.pushChanged(changed)       // evaluate only these, next frame
  }
</script>

<SvGridAlerts
  data={rows}
  columns={exprColumns}
  getRowId={(r) => r.id}
  watch={false}
  onReady={(h) => (alerts = h)}
  bind:formats={alertFormats} />

The handle also exposes reseed(allRows) (silently re-arm edges after a full data reset) and flush() (run any pending pass immediately). For big live feeds, prefer dataChange rules (fire once when a row crosses the line) over relativeChange (fires on every move), and keep actions toast-only to avoid conditional-format churn.

On a busy feed many rows can cross a threshold every second. Evaluation stays cheap, but a nonstop stream of toasts is disruptive and repaints constantly. Set toastCooldownMs to rate-limit toasts to at most one per rule per interval - every event is still logged (the bell badge stays accurate), only the visible toast is throttled:

<SvGridAlerts ... watch={false} onReady={(h) => (alerts = h)} toastCooldownMs={6000} />

The fired-alert log

The bell badge shows the unacknowledged count. Clicking it opens SvAlertsPanel - a drawer listing fired alerts newest-first, filterable by severity, with Acknowledge, Clear, and Go to row (wire onJump to scroll/select the row).

More examples

Styling rules

Alert rules are not just notifications: a highlight or badge action becomes live conditional formatting, painted through the grid's own format pipeline. A server fleet lights up by rule - hot CPU turns amber, near-full disks turn red via a cross-column rule (used / total > 0.9). Randomise the load and the colours follow. Add your own styling rule in the visual builder.

Open the live example: Styling rules (Alerts)

KPI & aggregate alerts

Alerts that watch a whole-table total, not just a row. An aggregate-scope rule fires once when SUM(revenue) crosses the company target; a row rule flags any region trailing its own target. Close a few deals and watch the aggregate alert fire the moment the total clears the line. Aggregate rules use the expression language's SUM / AVG / COUNT reducers.

Open the live example: KPI & aggregate alerts (Alerts)

Validation guardrails

A validation-trigger alert is evaluated on edit and can veto the change. A budget sheet is editable, and two guardrail rules block bad edits: a negative amount, or an amount over that line's budget. The pure engine is wired into the grid's per-column validate hook - the blessed integration point for prevent-edit. Toggle a guardrail off to allow the edit through.

Open the live example: Validation guardrails (Alerts)

Alerts operations console

A full monitoring app: an Outlook-style navigation pane (SvNavPane) on the left - a module rail (Monitor / Rules / Reports) plus badged folders (Critical / Warnings / Healthy and per-region) - filtering a live fleet grid on the right. Alert rules watch every host regardless of the folder you are viewing, paint the rows, and feed the bell and the fired-alert panel. Module buttons open the rule manager and the report panel.

Open the live example: Alerts operations console (Alerts)

See also

Live examples

  • Alert Rules engine - A live trading desk where end users define alert rules at runtime - no code - that watch the data and react: raise a toast, tint the row, flash the cell, or log it. A visual condition builder (or free-text expression) reuses the grid's own filter operators; rules persist to localStorage and export as shareable JSON. The bell opens the fired-alert log. Engine: @svgrid/enterprise.
  • Styling rules - Alert rules are not just notifications: a highlight or badge action becomes live conditional formatting, painted through the grid's own format pipeline. A server fleet lights up by rule - hot CPU turns amber, near-full disks turn red via a cross-column rule (used / total > 0.9). Randomise the load and the colours follow. Add your own styling rule in the visual builder.
  • KPI & aggregate alerts - Alerts that watch a whole-table total, not just a row. An aggregate-scope rule fires once when SUM(revenue) crosses the company target; a row rule flags any region trailing its own target. Close a few deals and watch the aggregate alert fire the moment the total clears the line. Aggregate rules use the expression language's SUM / AVG / COUNT reducers.
  • Validation guardrails - A validation-trigger alert is evaluated on edit and can veto the change. A budget sheet is editable, and two guardrail rules block bad edits: a negative amount, or an amount over that line's budget. The pure engine is wired into the grid's per-column validate hook - the blessed integration point for prevent-edit. Toggle a guardrail off to allow the edit through.
  • Alerts operations console - A full monitoring app: an Outlook-style navigation pane (SvNavPane) on the left - a module rail (Monitor / Rules / Reports) plus badged folders (Critical / Warnings / Healthy and per-region) - filtering a live fleet grid on the right. Alert rules watch every host regardless of the folder you are viewing, paint the rows, and feed the bell and the fired-alert panel. Module buttons open the rule manager and the report panel.

Related articles