@casoon/opengrid
v0.13.0
Published
Accessible data grid, table and pivot as web components, driven by a portable Rust/WASM query engine — with React, Vue and Svelte components.
Maintainers
Readme
opengrid
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::partfor 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/opengridThe 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, svelteimport { 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
- The public API — elements, attributes, events, the view, styling, texts, errors
- Guides and the project page
- In a chat client —
the grid as an MCP App,
@casoon/opengrid-mcp(not released yet)
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"(ortreegridwhen grouped) where interaction needs it: row and column headers,aria-rowcountfor 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.
