bo-grid v3.1.0

Get started

.md

Quick start

Install bo-grid and render a first grid in Svelte, React, Vue or plain JavaScript.

Install

npm i bo-grid

Svelte 5 is a peer dependency. React and Vue are optional peers, needed only for bo-grid/react and bo-grid/vue.

A first grid

Give the grid rows (each with an id) and columns. A column’s type picks how its values show: price, percent, volume, date, heatmap, sparkline and more. The tabs follow the framework chosen in the top bar.

<script lang="ts">
  import { Grid, type ColumnDef } from 'bo-grid';

  const columns: ColumnDef[] = [
    { type: 'text', key: 'symbol', header: 'Symbol' },
    { type: 'price', key: 'price', header: 'Price', flash: 'auto' },
    { type: 'percent', key: 'change', header: 'Chg %' },
    { type: 'volume', key: 'volume', header: 'Volume' },
  ];
  let rows = $state([
    { id: 1, symbol: 'VNM', price: 68.5, change: 1.2, volume: 1_204_000 },
    { id: 2, symbol: 'FPT', price: 132, change: -0.4, volume: 860_500 },
  ]);
</script>

<Grid {rows} {columns} height={400} />

The same grid, running: sort a column from its header, resize one from its edge, or select a range to see its sum.

quick-start.svelte GitHub ↗

The three props every grid takes:

Grid props from the types
rows* GridRow[]

The data: one plain object per row, each with a unique id, a number or a string (or name another key with getRowId).

Example
let rows: GridRow[] = $state([
  { id: 1, sym: 'VNM', last: 68.5 },
  { id: 2, sym: 'FPT', last: 121.3 },
]);
columns* ColumnDef[]

The columns, in display order. A column's type picks how its values show, sort and filter.

Example
const columns: ColumnDef[] = [
  { type: 'text', key: 'sym', header: 'Symbol', width: 90 },
  { type: 'price', key: 'last', header: 'Last', flash: 'auto' },
];
height* number | string

Viewport height. A number is the scroll viewport's pixel height (the grid's total height is that plus header/toolbar/footer chrome). A CSS string (e.g. '100%', '80vh', '480px') sizes the whole grid element and the viewport auto-fits the space left after the chrome — give the grid a sized parent (or use '100%' inside a flex/grid cell).

Example
<Grid {rows} {columns} height="100%" />

A live feed

For a busy feed, keep the rows as plain objects and let the grid write the ticks. createTickStream coalesces messages per key and hands the grid one batch a frame; patchRows repaints only the cells that changed.

<script lang="ts">
  import { Grid, type GridApi } from 'bo-grid';
  import { createTickStream } from 'bo-grid/realtime';

  let rows = $state.raw(initialQuotes); // plain objects: the grid writes the ticks
  let api: GridApi;
  const stream = createTickStream<string, Partial<Quote>>({
    apply: (batch) => api.patchRows(batch), // repaints only the cells that changed
  });
  stream.start();
  socket.onmessage = (e) => {
    const q = JSON.parse(e.data);
    stream.push(q.symbol, q);
  };
</script>

<Grid {rows} {columns} getRowId={(r) => String(r.symbol)} onReady={(a) => (api = a)} height={400} />

Past about 10,000 messages a second, read the socket in a worker with serveFeed and connectFeed: the main thread then takes one batch a frame instead of every message.

Next