@casoon/opengrid

Accessible data grid, table and pivot as web components, driven by a portable Rust/WASM query engine — with React, Vue and Svelte components.
2,628 1
Install
npm install @casoon/opengrid
Latest Version:0.13.0
Vue:3
License:MIT OR Apache-2.0
Last Updated:Oct 14, 2026
Links: GitHub  ·  npm
Maintainer: jseidel

opengrid

npm licence

Data grid, table and pivot as Web Components, built to be accessible and machine-readable — driven by one query engine that runs in the browser (WebAssembly), on a server (PostgreSQL), or split between the two, with the same results everywhere.

  • <opengrid-grid> — sorting, filtering, search, facets, grouping with totals, selection, editing, virtualized or paged; operated from the keyboard.
  • <opengrid-table> — a plain semantic <table> for displaying data.
  • <opengrid-pivot> — a pivot with subtotals and a grand total, from a server or from the engine in the tab.
  • Column titles — the page names its columns, in its own language, wherever the grid names them.
  • Export — what the reader sees, every match of it, as CSV or JSON; XLSX from the server.
  • A resource report — every answer as an event (where it ran, how long, how big), and what the engine holds in memory.
  • Data without JavaScript — a page can put its own <table> inside an element, for readers and crawlers that run no script.
  • Five built-in looks — theme="paper", your own --og-* properties on top, and ::part for every element.

Live demos

The same 17 demos in every framework, each with its source, its data and options to change live:

JavaScript React Vue Svelte Angular

Start with the overview, the grouping, the 100,000 rows in a worker or the looks.

Install

npm install @casoon/opengrid

The package holds the elements and the query engine. With a bundler, import from @casoon/opengrid; without one, see Installation.

Data in the browser

The engine reads a CSV against a schema — it never guesses types.

<opengrid-grid label="Orders" datasource="orders" columns="id,customer,amount"></opengrid-grid>

<script type="module">
  import { connect, createLocalProvider } from "@casoon/opengrid";
  import init, { Engine } from "@casoon/opengrid/engine/opengrid_wasm.js";

  await init();
  const engine = new Engine();
  const csv = await (await fetch("/orders.csv")).arrayBuffer();
  const schema = await (await fetch("/orders.schema.json")).text();
  engine.load_csv("orders", new Uint8Array(csv), schema);

  connect(document.querySelector("opengrid-grid"), {
    provider: createLocalProvider(engine),
  });
</script>
{
  "fields": [
    { "name": "id", "type": "int64", "nullable": false },
    { "name": "customer", "type": "utf8", "nullable": true },
    { "name": "amount", "type": { "decimal": { "precision": 12, "scale": 2 } }, "nullable": true }
  ]
}

createWorkerProvider() runs the same engine in a worker instead.

Data from a server

opengrid-server answers the same queries on a server — the browser sends a query object, never SQL, and the server enforces tokens, a per-tenant row filter and a field allowlist. It knows no database: your program hands it its sources as connectors, and PostgreSQL is one reference among them.

import { connect, createRestProvider } from "@casoon/opengrid";

connect(document.querySelector("opengrid-grid"), {
  provider: createRestProvider({ url: "https://example.org", source: "orders", token: "…" }),
});

See Where queries run.

React, Vue, Svelte

One package: the components are its subpaths, and the framework is an optional peer.

npm install @casoon/opengrid react   # or vue, svelte
import { OpengridGrid } from "@casoon/opengrid/react";   // or /vue, /svelte

<OpengridGrid label="Orders" datasource="orders" columns="id,customer,amount"
              provider={provider} view={view} onViewChange={setView} />

Angular, Astro and server-rendered pages use connect directly — Frameworks.

Looks

A grid without any page CSS wears Base. theme picks another of the five built-in looks — base, paper, violet, orange, dark — on all three elements:

<opengrid-grid theme="dark" label="Orders" datasource="orders"></opengrid-grid>
/* The page's own properties win over the look. */
opengrid-grid { --og-accent: #0f766e; --og-row-height: 36px; }

The focus ring, the selection bar and the forced-colours palette stay what they are in every look. The fonts are named, not loaded: a page that wants Geist or IBM Plex Sans hosts them. See Styling.

Export

import { loadOpengrid, exportRows } from "@casoon/opengrid";

const { module } = await loadOpengrid();
const query = module.get_query(grid);               // the reader's view, without a window
const blob = await exportRows(provider, query, { format: "csv" });

CSV per RFC 4180 with a guard against formula injection, or JSON; through createRestProvider also XLSX, written by the server (format: "xlsx"). A pivot exports as shown with get_pivot. See Export.

Documentation

Accessible and machine-readable: the aim

opengrid is meant to be more than a WebAssembly engine that draws a grid. Its data should reach everyone and everything that reads a page: a person using a keyboard or a screen reader, and a program — a test, a browser agent, an export. How it is built toward that:

  • One structure for people and programs. A native <table> where reading is all there is to do, role="grid" (or treegrid when grouped) where interaction needs it: row and column headers, aria-rowcount for the whole result behind a virtualized window, aria-sort, aria-selected, a name for every control. The accessibility tree a screen reader reads is the one an automation tool or an AI agent reads.
  • Designed for the keyboard. The WAI-ARIA grid pattern for the keys, nothing that needs dragging, and one polite live region for every change of state.
  • Open data at every step. The schema is a JSON document, a query is a JSON AST, the view is JSON, an export is CSV, JSON or XLSX, and a page can write its data as a plain table inside the element for readers that run no script.
  • Tested, not assumed. axe-core runs over every state of the end-to-end suite; target sizes, reflow at 320 px and forced colours are tests; the announcements are recorded in order.

This is not a statement of conformance yet. A pass with a screen reader is still to come (#5), and a conformance report follows it. What is tested and what is not: Accessibility.

Status

Pre-1.0: a minor version may change the API, a patch version does not (CHANGELOG).

Licence

MIT OR Apache-2.0.

Related Packages

@colletdev/docs

Collet component library documentation — API reference, framework guides, and AI...

13,399
@chialab/plasma

Generate Custom Elements wrappers for Angular, React, Svelte and Vue.

3,951 2
@tanstack/vue-virtual

Headless UI for virtualizing scrollable elements in Vue

102,498,749 7,171
@accesslint/storybook-addon

Catch accessibility violations in your Storybook stories as you develop

3,861 13
iconsax

Iconsax web component — 1200+ free icons out of the box, Pro icons via `iconsax...

37,176

Version History

Version Released License
0.13.0 MIT OR Apache-2.0
0.12.0 MIT OR Apache-2.0
0.11.0 MIT OR Apache-2.0
0.10.0 MIT OR Apache-2.0
0.9.0 MIT OR Apache-2.0