← Live demo

One core. Three interfaces.

The Angular, React and Vue grids do not each re-implement filtering, sorting, dates, parsing and export. They share one framework-agnostic package, and only the UI layer is written per framework.

Angular, React and Vue grids on top of one shared core package, which shares its query contract with Inandu.Grid.Extensions on .NET

What lives where

LayerHoldsDoes not hold
UI
grid-angular grid-react grid-vue
The component, the headless hook / signals / composables, rendering, focus and keyboard handling, virtual scroll, theming, the server data hook. Any rule about what a value means: how it is compared, filtered, formatted, parsed or exported.
Core
@inandu-solutions/grid-core
Column filters, sorting, date and number formatting, aggregates, tree flattening, paste and draft parsing, CSV / Excel markup / PDF helpers, translated messages in 5 languages. Frameworks, components and the DOM (the single exception is downloadBlob).
Server
Inandu.Grid.Extensions (.NET)
Turning the grid's query string into an IQueryable: filters, sorts, paging, keyset cursors, deny-by-default field allow-list. Any client code. It only agrees with the clients on the wire format.

What this buys you

The contract with the server

The query the grids send and what the .NET extensions accept are checked against one shared fixture, server-queries.json. The same cases run on the TypeScript side (the clients) and on the .NET side (the server), so a change to the wire format fails a test on whichever side did not follow.

Use the core on its own

npm install @inandu-solutions/grid-core

import { formatCellValue, matchesColumnFilter, escapeCsvValue } from '@inandu-solutions/grid-core';

formatCellValue('2024-01-05', 'date', 'YYYY-MM-DD', 'en-US'); // "2024-01-05", in every time zone
escapeCsvValue('=HYPERLINK("http://example.com","x")');       // opens as text, not as a formula

grid-core on GitHub · npm · grid-angular · grid-react · grid-vue · Inandu.Grid.Extensions