Lattice Grid Buy a licence

angular data grid

Angular Data Grid: A Component For Every View

The Angular data grid, licensed per domain. Lattice Grid gives Angular a standalone component for every view it draws: the grid, the stat tiles, a chart, the board, the plan, the dashboard layout and the tab strip. Each one is compiled ahead of time, the way every Angular library you install is, so the build that goes to production is the build you already run.

Add it to an Angular app

One package. The Angular components are part of it, at their own import path, so there is one install, one version number and one licence to keep track of.

npm install @toclocoinc/lattice-grid

Import the components from @toclocoinc/lattice-grid/angular and load the stylesheet with import '@toclocoinc/lattice-grid/css'. Angular is an optional peer dependency, so a project that is not an Angular one installs nothing extra and sees no warning, and the components themselves ask only for Angular 17 or newer. They run in the browser, so a server-rendered page sends the empty host element and the view is built on hydration.

import { Component, viewChild } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import { createGrid } from '@toclocoinc/lattice-grid';
import { createKPI } from '@toclocoinc/lattice-grid/modules/kpi';
import { createChart } from '@toclocoinc/lattice-grid/modules/charts';
import '@toclocoinc/lattice-grid/css';
import {
  LatticeGridComponent, LatticeKpiComponent, LatticeChartComponent, provideLattice,
} from '@toclocoinc/lattice-grid/angular';

@Component({
  selector: 'app-dashboard',
  imports: [LatticeGridComponent, LatticeKpiComponent, LatticeChartComponent],
  template: `
    <lattice-grid #grid name="quakes" [config]="config" [quickFilter]="search()"
                  (cell-changed)="save($event)" />
    <lattice-kpi  gridName="quakes" [config]="{ tiles }" />
    <lattice-chart gridName="quakes" [config]="{ type: 'bar', x: 'region', y: 'count' }" />
  `,
})
export class Dashboard {
  // The live grid, the same object createGrid returns.
  grid = viewChild<LatticeGridComponent>('grid');
}

// Each factory is injected rather than imported by the library, so an
// application that shows a grid downloads the grid and never the board,
// the plan or the chart types.
bootstrapApplication(Dashboard, {
  providers: [provideLattice({ createGrid, createKPI, createChart })],
});

A component per view, not a grid and seven lifecycle hooks

<lattice-grid> is the grid, and [latticeGrid] puts the same thing on an element your template already owns. Beside them are <lattice-kpi>, <lattice-chart>, <lattice-kanban>, <lattice-gantt>, <lattice-layout> and <lattice-tabs>, so a whole dashboard is a template rather than a page of ngAfterViewInit and ngOnDestroy pairs written once per view. Every grid event is an output under its kebab-case name, so (cell-changed), (cell-edit-start) and (selection-changed) bind the way any Angular output does, and (grid-ready) hands you the live grid.

Views find their grid, whatever order they mount in

Give a grid a name and any grid-bound view takes that name through gridName. A stat panel written above its grid in the template mounts itself the moment the grid arrives, which is the case a template reference cannot answer. A tab's content is your own <ng-template latticeTab="id">, rendered inside the strip with your injectors above it, and configuration-driven tabs still work on the same strip. The data router is a service: put provideLatticeRouter in a component's providers and one feed drives every view underneath it, created and torn down with that component.

Fast by default, in a zone or without one

The grid paints on its own schedule rather than Angular's, so scrolling a million rows costs no change detection and an output nobody bound costs nothing at all. Zoneless change detection and OnPush both work with nothing to configure, and a host component that never re-renders still holds a fully live grid. A changed input reaches the view already on screen, so scroll position, selection, expansion and any open editor survive it, and an input a view cannot take while it is running is named in a warning rather than dropped in silence. ngOnDestroy takes the whole thing down and leaves no interval or listener behind.

The integration reference lists every component, its inputs and its outputs, and the module map shows what each view costs to add. If you would rather not take a component at all, createGrid works on a host element you own, and the custom elements give you a tag per view with no bundler. Type declarations ship with the package.

One grid, every framework

Lattice Grid is not framework-coupled. The same engine renders in Angular, in another framework, or on a plain HTML page, and behaves identically in each, so a team moving between them learns one API and tests one set of behaviours. What changes is only the way a view is declared: an Angular template, a React component, a Vue component, a Svelte component, or a <lattice-grid> tag on a page with no build step at all. Type declarations ship with the package, so TypeScript projects get full IntelliSense with no extra setup.

Priced per domain, not per developer

A licence covers the domain the grid runs on, not the person: add developers, contractors and agencies without adding cost, and without an audit conversation. Development on localhost is free and needs no key. Deployment is $1,000 per domain, or $10,000 for a wildcard covering every subdomain, both with a year of support and unlimited developers.

By feature

Full source, a live embed and Angular-specific caveats for each: