Ultimate Data Grid

A fully open-source, high-performance data grid with zero runtime dependencies. One engine, every framework.

MIT Licensed Zero Dependencies TypeScript 6 Frameworks
See it in action ↓

Built for Performance

Everything you need in a data grid, nothing you don't.

Virtual Scrolling

Both axes virtualized. Handles millions of rows at 60 fps with a tiny DOM footprint.

Multi-Sort

Click to sort. Ctrl+click to add secondary sorts. Three-state cycle: asc, desc, off.

Filter Expressions

Type >50000, 2020..2023, or ^Alice directly into the filter row. No dropdowns needed.

Drag Select

Click+drag for ranges. Ctrl+drag to add or remove. Supports both row and cell selection modes.

Light & Dark Mode

CSS custom properties with automatic OS detection. Override with one class toggle.

Zero Dependencies

Pure vanilla TypeScript core. No bloat, no supply-chain risk, no version conflicts.

Spreadsheet Mode

Cell-level selection with Excel-style ranges, row headers, keyboard navigation, and A1-notation coordinates.

Plugin Architecture

Extend with custom cell renderers, filter logic, and event handlers without forking.

Try It Live

Showing 2000 of 2000 rows  ·  Sort: none  ·  Selected: 0

Every Framework, One API

Thin wrappers around the same engine. Pick your framework.

$ npm install @ultimate-grid/core
Usage
import { createGrid } from '@ultimate-grid/core';
import '@ultimate-grid/core/styles/ugrid.css';

const api = createGrid({
  container: document.getElementById('grid'),
  columnDefs: [
    { key: 'name',   field: 'name',   headerName: 'Name'   },
    { key: 'salary', field: 'salary', headerName: 'Salary' },
    { key: 'joined', field: 'joined', headerName: 'Joined' },
  ],
  rowData: [
    { name: 'Alice', salary: 95000, joined: '2020-03-01' },
    { name: 'Bob',   salary: 72000, joined: '2018-07-15' },
  ],
  selectionMode: 'multi',
});

// API methods
api.setSortModel([{ colId: 'name', direction: 'asc' }]);
api.setFilterModel({ salary: { value: '>80000' } });
$ npm install @ultimate-grid/core @ultimate-grid/react
Usage
import { UltimateGrid } from '@ultimate-grid/react';
import '@ultimate-grid/core/styles/ugrid.css';

function App() {
  const [gridApi, setGridApi] = useState(null);

  return (
    <UltimateGrid
      columnDefs={columnDefs}
      rowData={rowData}
      selectionMode="multi"
      rowHeight={36}
      cellRenderer={customRenderer}
      onGridReady={(api) => setGridApi(api)}
      onSortChanged={handleSort}
      onFilterChanged={handleFilter}
      onSelectionChanged={handleSelection}
    />
  );
}
$ npm install @ultimate-grid/core @ultimate-grid/vue
Usage
<script setup>
import { UltimateGrid } from '@ultimate-grid/vue';
import '@ultimate-grid/core/styles/ugrid.css';

const columnDefs = [/* ... */];
const rowData = ref([/* ... */]);

function onGridReady(api) {
  // Store api reference
}
</script>

<template>
  <UltimateGrid
    :column-defs="columnDefs"
    :row-data="rowData"
    selection-mode="multi"
    :row-height="36"
    @grid-ready="onGridReady"
    @sort-changed="onSortChanged"
    @filter-changed="onFilterChanged"
    @selection-changed="onSelectionChanged"
  />
</template>
$ npm install @ultimate-grid/core @ultimate-grid/svelte
Usage
<script lang="ts">
  import UltimateGrid from '@ultimate-grid/svelte';
  import '@ultimate-grid/core/styles/ugrid.css';

  let gridApi = null;
  const columnDefs = [/* ... */];
  let rowData = [/* ... */];
</script>

<UltimateGrid
  {columnDefs}
  {rowData}
  selectionMode="multi"
  rowHeight={36}
  onGridReady={(api) => gridApi = api}
  onSortChanged={handleSort}
  onFilterChanged={handleFilter}
  onSelectionChanged={handleSelection}
/>
$ npm install @ultimate-grid/core @ultimate-grid/angular
Usage
import { UltimateGridComponent } from '@ultimate-grid/angular';
import '@ultimate-grid/core/styles/ugrid.css';

@Component({
  standalone: true,
  imports: [UltimateGridComponent],
  template: `
    <ultimate-grid
      [columnDefs]="columnDefs"
      [rowData]="rowData"
      selectionMode="multi"
      [rowHeight]="36"
      [cellRenderer]="cellRenderer"
      (gridReady)="onGridReady($event)"
      (sortChanged)="onSortChanged($event)"
      (filterChanged)="onFilterChanged($event)"
      (selectionChanged)="onSelectionChanged($event)"
    />
  `,
})
export class AppComponent {
  columnDefs = [/* ... */];
  rowData = [/* ... */];
}
$ npm install @ultimate-grid/core @ultimate-grid/angularjs
Usage
// Register the module
angular.module('myApp', ['ultimateGrid'])

// In your template:
<ultimate-grid
  column-defs="vm.columnDefs"
  row-data="vm.rowData"
  options="vm.gridOptions"
  selection-mode="multi"
  on-grid-ready="vm.onGridReady(api)"
  api="vm.gridApi">
</ultimate-grid>

// Events broadcast to $rootScope:
$rootScope.$on('ugrid:selectionChanged', function(_, e) {
  // No $scope.$apply() needed — digest-safe
  vm.selected = e.selectedRowIds.length;
});

Get Started

Install the core and your framework wrapper of choice.

Clone & Run Locally

git clone https://github.com/harvey-withington/ultimate-grid.git
cd ultimate-grid
npm install
npm run dev

Install via npm

npm install @ultimate-grid/core

# Framework wrappers (pick one)
npm install @ultimate-grid/react
npm install @ultimate-grid/vue
npm install @ultimate-grid/svelte
npm install @ultimate-grid/angular
npm install @ultimate-grid/angularjs

Run the Demos

npm run dev           # Core (Vanilla JS)
npm run dev:react     # React
npm run dev:vue       # Vue 3
npm run dev:svelte    # Svelte
npm run dev:angular   # Angular 17+
npm run dev:angularjs # AngularJS 1.x