bo-grid v3.1.0

Export & API

.md

Grid API

The grid's handle for actions that are not state, such as scrolling to a row, focusing a cell, saving a layout or patching live rows.

Most of the grid is driven by props: rows, columns, sort, filters. Some things are actions rather than state, with no resting value a prop could hold: scroll to this row, focus that cell, download the current view, save the layout. For those the grid hands you one object, the grid API, through onReady.

Each button calls one API method. Resize or move a column, then save the layout, change it again and restore it.

grid-api.svelte GitHub ↗

Getting the handle

onReady is called once, when the grid mounts, with the API object:

<script lang="ts">
  import { Grid, type GridApi } from 'bo-grid';
  let api = $state<GridApi>();
</script>

<button onclick={() => api?.scrollToRow('ORD-1042', 'center')}>Find order</button>
<Grid {rows} {columns} height={480} onReady={(a) => (api = a)} />

In React and Vue the same object is the component’s ref (ref.current in React, the template ref’s api in Vue); see React, Vue & more.

Methods

MethodWhat it does
scrollToRow(id, align?)Scroll a row into view; align is 'nearest' (default), 'start', 'center' or 'end'
focusCell(rowId, columnKey)Focus and select one cell
getFocusedCell()The focused { row, column }, or null
getSelectedRows()The ticked rows (with rowSelection), in view order
autosizeColumns(keys?)Fit columns to their content, as the column menu’s Autosize does
exportCSV(filename?)Download the current view, after filters and sort, as CSV
getState() / applyState(state)Save and restore the user’s layout (below)
patchRows(patches)Write live values into rows in place; see Live updates
refresh()Re-run sort and filters against values changed in place
flashCells(options?)Flash cells on demand; see Cell flashing
pinRow(id, pinned?) / getPinnedRowIds()Pin rows above the scroll from code
openFind(query?)Open the find bar (with findBar)

Methods that look a row up by id (scrollToRow, focusCell) return false when the row is not in the current view: filtered out, on another page, or in a grid backed by a server source.

Saving a layout

getState() returns the user’s layout as one plain, JSON-safe object: column order, widths, hidden columns, pinned columns, pinned rows, sorts and filters. Keep it wherever you keep user settings, per user or per workspace, and give it back with applyState(saved):

const saved = api.getState();
localStorage.setItem('orders-layout', JSON.stringify(saved));

// later
api.applyState(JSON.parse(localStorage.getItem('orders-layout') ?? 'null'));

applyState fits the saved layout onto the columns as they are now:

  • Entries for columns that no longer exist are dropped.
  • A new column lands where it is declared, after the nearest column declared before it.
  • Malformed fields are ignored rather than thrown on.
  • A state from another version of the format is refused whole (applyState returns false), because half a layout is worse than none.

The same rules are exported as reconcileState(saved, columnKeys), for a server that wants to apply them itself. For the simple case, persistKey saves the layout in the browser’s local storage with no code.

Also exported

Besides Grid and its types, the package exports helpers you can use on their own:

GroupExports
ComponentsGrid, Sparkline
FormattingfmtPrice, fmtPercent, fmtVolume, fmtDate, fmtCurrency, relativeTime
Dataaggregate, pivot, sortRows, heatColor, resolveColumns, buildMergePlan, colSpanRow
Export and importtoCSV, exportCSV, exportXLSX, parseCSV, parseCSVMatrix, parseTSV, parseJSON, parseRows, rowsFromObjects, toHTMLTable, printTable, escapeHTML
Server datacreateArraySource
Theming and textthemeVars, themePresets and the preset token maps, DEFAULT_LABELS, resolveLabels
Layout statereconcileState, GRID_STATE_VERSION
CanvasdrawCandles, setupHiDpiCanvas (draw candlesticks on a canvas of your own)

Realtime and trading helpers live in their own entries, bo-grid/realtime, bo-grid/trading and bo-grid/ladder. Every prop and method, with its type, is in the Props reference.

Reference

Grid props from the types
onReady (api: GridApi) => void

Called once, when the grid mounts, with a handle for imperative actions: scrollToRow, focusCell, patchRows, getSelectedRows, autosizeColumns, exportCSV, getState / applyState and more.

Example
<Grid {rows} {columns} height={480} onReady={(a) => (api = a)} />
persistKey string Default undefined

Remember the user's layout (column order, widths, hidden and pinned columns, pinned rows) in localStorage under this key.

Grid API from the types
scrollToRow (key: string | number, align?: ScrollAlign): boolean

Scroll a row into view by its id; align is 'nearest' unless given. Returns false when the row is not in the current view (filtered out, not loaded, or unknown).

Example
api.scrollToRow(order.id, 'center');
focusCell (rowKey: string | number, columnKey: string): boolean

Focus (and select) one cell by row id and column key. Returns false when the row or column is not currently visible.

Example
if (!api.focusCell(row.id, 'qty')) api.scrollToRow(row.id);
getFocusedCell (): { row: GridRow; column: ColumnDef } | null

The focused cell's row and column, or null when no data cell has focus (nothing focused yet, or the focus is on a group row). For hotkeys that act on the row the user is on.

Example
const cell = api.getFocusedCell();
if (cell) openTicket(cell.row);
getSelectedRows (): GridRow[]

Ticked rows (needs rowSelection), in view order.

Example
const ids = api.getSelectedRows().map((row) => row.id);
autosizeColumns (keys?: string[]): void

Fit columns to their content, as the column menu's Autosize does. All resizable columns when keys is omitted. The other columns keep their widths (flex ones are held where they are).

Example
api.autosizeColumns(['sym', 'name']);
exportCSV (filename?: string): Promise<void>

Download the current view (after filter and sort) as CSV, named export.csv unless filename is given.

Example
await api.exportCSV(`orders-${new Date().toISOString().slice(0, 10)}.csv`);
getState (): GridState

Snapshot of the user's layout: order, widths, hidden, pins, sorts, filters. A plain object, safe to JSON.stringify and store.

Example
localStorage.setItem('orders-layout', JSON.stringify(api.getState()));
applyState (state: unknown): boolean

Restore a snapshot, reconciled against the columns as they are now. Returns false when the state is unusable (foreign version, not an object).

Example
const saved = localStorage.getItem('orders-layout');
if (saved) api.applyState(JSON.parse(saved));
patchRows (patches: Iterable<readonly [string | number, Record<string, unknown>]>): number

Realtime fast path: write [rowId, fields] patches into the rows in place and repaint only the rendered rows they change. Rows may be plain objects (no $state proxy) — far cheaper per write in a busy feed. Feed it a tick stream: createTickStream({ apply: (b) => api.patchRows(b) }). Sort and filter catch up on the next view change, as for any live data (or at once, with liveSort). A patch's id is the row's getRowId value (row.id unless set). Returns how many rows changed.

Example
api.patchRows([
  [1, { last: 68.6, vol: 1_204_300 }],
  [2, { last: 121.1 }],
]);
refresh (): void

Re-run filter and sort against the rows' current values. Values that change in place (a feed) never re-sort the view by themselves — that would mean re-sorting on every tick — so call this when the order should catch up, e.g. every second on a "top movers" board (or use liveSort).

Example
const timer = setInterval(() => api.refresh(), 1000);
flashCells (opts?: FlashCellsOptions): number

Flash cells on demand — a fill, an alert, a row to notice — with the tick animation, whether or not their values changed. Only rows on screen flash. Value cells flash (numbers, text); cells that draw their own content (badges, sparklines, components) do not. Returns how many rows it flashed.

Example
api.flashCells({ rows: [fill.orderId], dir: fill.side === 'buy' ? 'up' : 'down', ms: 800 });
pinRow (key: string | number, pinned?: boolean): boolean

Pin a row above the scroll (or unpin it with pinned: false), as the row menu does under rowPinning; pinned is true unless given. The row stays in the body too. Returns false when no row has that id.

Example
api.pinRow(row.id);
getPinnedRowIds (): (string | number)[]

Ids of the rows pinned at runtime, in pin order.

Example
for (const id of api.getPinnedRowIds()) api.pinRow(id, false);
openFind (query?: string): void

Open the find bar (findBar), optionally searching for query at once.

Example
api.openFind('VNM');