blog
JavaScript Data Grid Engineering Notes
Notes from building it. What we measured, why the grid is built the way it is, and what it means for the people using it all day.
-
about 9 min
JavaScript form library for data apps: the Lattice form
One product for the table and the form that edits it. Bind a form to a grid row, validate, and register your own custom controls once to use like built-ins.
-
about 7 min
Revenue by Customer Segment: Join a Grid, Then Group It
Join two tables in a JavaScript grid: bring segment across from a customers grid, group orders by it, and keep the segment totals moving with both tables' filters.
-
about 4 min
Data grid theming: 4 presets, dark mode, 1.103
One token contract now carries four presets and dark mode across the grid, form, Gantt, Kanban, calendar and more, plus four new form controls, all live.
-
about 7 min
Units and Revenue by SKU: Unnest Order Lines
Flatten a nested array into a JavaScript table: unnest each order's line items and total units and revenue by SKU, in a derived grid that follows the orders grid's filters.
-
about 7 min
Loss-Making Orders: an Exceptions Grid, Not an Export
A conditional row filter in a JavaScript grid: a live list of loss-making orders, built from your orders grid with where, updated the moment cost passes amount.
-
about 2 min
Barcode Cells in a Data Grid: Code 128, EAN-13 and Data Matrix From the Cell Value
Barcode cells in a data grid: set a column to the barcode renderer and Code 128, EAN-13 or Data Matrix is drawn as inline SVG from the cell value.
-
about 5 min
JavaScript form library: 5 new controls, 1.101
A date range picker, list box, speed dial, toggle with on and off text, and barcodes with Data Matrix join the form and grid, each with a live example.
-
about 8 min
Overdue Orders: a Derived Grid That Maintains Itself
Build an overdue orders exception report as a derived data grid from your orders grid, filtered with where, so it never goes stale when someone filters the table.
-
about 4 min
Editable data grid in JavaScript: forms and touch
One record editor spread over several layout cells now validates, locks and saves as one form, and the boards, Gantt, calendar and scheduler edit by touch.
-
about 7 min
Top Customers by Revenue: the 80% Cutoff
Pareto analysis in JavaScript: a top-customers grid from your orders grid, kept until the running revenue share crosses 80%, and re-applied whenever the orders are filtered.
-
about 7 min
Top 3 Products Per Region: a Derived Grid with limitPer
Top N per group in JavaScript: the best three products per region from your orders grid, with groupBy and limitPer, so one filter moves both and the ranking never drifts.
-
about 6 min
Sales Leaderboard: Top Five Reps From a Derived Grid
Show the top N rows in a JavaScript grid: a top five sales leaderboard built from your orders grid by rep and revenue, so one filter moves both.
-
about 7 min
Monthly Revenue Trend Grid That Feeds a Line Chart
Group by month in JavaScript with a derived grid: bucket orders, sum revenue and feed a chart from grid data that stays in step once someone filters the table.
-
about 11 min
Chart a Derived Grid: Source and Derived Data, One Chart
Bind a chart to a derived grid and it follows the parent live. Union the source grid with the derived one and a single chart overlays both, on one chart or two axes.
-
about 6 min
Region by Category Revenue Matrix From One Order Grid
A pivot table in JavaScript, built from one order grid: a region by category revenue matrix that groups and sums live, so it never disagrees with the filtered table.
-
about 6 min
Revenue by Region: a Derived Grid, Not a Second Query
Group by region in a JavaScript data grid: a revenue summary table built from your orders grid, so one filter moves both and the numbers never disagree.
-
about 5 min
New shapes, moving pictures and measuring tools for your charts
Seventeen new chart types, charts that play through time, precise measuring and annotation, and labels that finally stay put.
-
about 5 min
We Migrated 166 Grids to Lattice Grid. Here's What Broke.
TOCLOCO moved its own product, DemandFlow, onto Lattice Grid across 166 grids. What it took, what broke in our grid and our own code, and what got better.
-
about 2 min
Lattice Grid 1.83: a data grid that is also a calendar
The same rows a grid holds now show as a calendar too, with drag-to-reschedule write-back, a working week view, and every framework adapter.
-
about 1 min
Lattice Grid 1.82: a grid that survives Back and Forward
On an htmx page, Back and Forward now bring a hydrated grid back live with its sort and filters intact, server-rendered types are respected, and viewers survive a swap.
-
about 4 min
One response for the grid and every dropdown in it
An editable grid needs its rows and the option lists behind its dropdown columns. With the Data Router one response carries both, and each dropdown follows its own route live.
-
about 2 min
Lattice Grid 1.81: presets that match their system's real shape
The four design-system presets now match Material 3, Bootstrap 5, Ant Design 5 and Fluent 2 in shape as well as colour, checked against a real, installed Material UI data grid.
-
about 3 min
Lattice Grid 1.80: design-system presets and a page that pages
Restyle the grid to Material 3, Bootstrap 5, Ant Design 5 or Fluent 2 with one stylesheet, read a live MUI theme straight in, and replace a Material UI data grid in one import.
-
about 2 min
Lattice Grid 1.79: loading rows, grouping on ClickHouse
A grid over a live source now shows its own loading state, groups by any column on ClickHouse and Elasticsearch, and keeps its KPI tiles honest over paged and pivoted data.
-
about 2 min
Lattice Grid 1.78: filter menus and pivots run in the engine
A pushdown grid now opens its filter menus instantly, pivots where the data lives, and lets select-all mean every matching row, not just the ones on screen.
-
about 4 min
The Pushdown Data Grid: One Query, Any Engine
One grid, one query shape, any engine. The pushdown source sends filters, sorts, grouping, pivots and aggregates to the database, and holds only the rows on screen.
-
about 4 min
Lattice Grid 1.77: dashboards from a spec, and Elasticsearch
Build a whole dashboard from one JSON spec, read Elasticsearch and OpenSearch directly, hand-order rows without losing a sort, and compare two extracts with a fix, not a workaround
-
about 4 min
Filter and Map Location Data in a JavaScript Grid
Give a table column a real shape, filter it by box, polygon or distance, draw it on a map, and read it from a GeoParquet file without loading more than the page in view.
-
about 2 min
Lattice Grid 1.74: one dark switch, many values in a cell, deck.gl
One theme switch reaching a whole dashboard, a list column type for many filterable values in one cell, deck.gl as a grid viewer, and volume in the candlestick pane.
-
about 3 min
Lattice Grid 1.76: ClickHouse, MotherDuck and the Leaflet map
A row form that adds a row, dropdowns that follow a live source, ClickHouse and MotherDuck as first-class sources, Leaflet joining deck.gl, and a cleaner annotation rail.
-
about 3 min
Lattice Grid 1.73: shapes in a column, and maps that ask the engine
A geometry column type with four spatial filters, GeoParquet read straight into DuckDB in the browser, a choropleth chart, and maps whose pan and zoom become a filter on the grid.
-
about 4 min
Reading Splunk Live in a Data Grid
Filter, sort and page a live Splunk search from an ordinary data grid. The grid writes the search string, Splunk does the work, and the credential never leaves the browser.
-
about 4 min
Lattice Grid 1.70: a lighter grid, and KPI tiles that know a dead feed
A quarter less to download, KPI tiles that grade freshness as well as value, text-only headings for wallboards, and an API reference with a page per module.
-
about 5 min
Numbers that keep moving after they are announced
Forty-seven FRED economic series with every revision kept. Rewind the whole dashboard to a date, or replay one series exactly as it was first announced against today.
-
about 4 min
An editable grid for your pandas DataFrame
Render a pandas DataFrame as an interactive, editable grid in a Jupyter notebook, then read every edit back in Python with dtypes preserved. The same grid runs in Dash.
-
about 6 min
One live feed, a whole screen of views
One live feed can drive several related grids and a chart at once. A router partitions the stream by a property so each decoupled view shows only its own slice.
-
about 3 min
Draw on the live numbers, not on a screenshot
Present the grid itself in a review and draw straight over it. Ring the line, arrow the outlier, highlight the total, all on real data that never changes underneath.
-
about 3 min
Private by default: the grid never phones home
The grid validates its licence in the browser and sends nothing anywhere. No licence server, no telemetry, and the only calls it makes go to your own data.
-
about 7 min
A grid over DuckDB, in the browser
Point Lattice Grid at a duckdb-wasm connection and it pushes filter, sort and paging down, and gets whole-dataset stats by pulling the set in or pushing the aggregation to DuckDB.
-
about 7 min
The column knows it holds metres
In most grids a unit is a formatter, and a formatter is a lie that shows the moment someone sorts. Lattice Grid makes a quantity a data type, so the column stays a number.
-
about 3 min
The table is the schema
htmx renders the table on the server; Lattice Grid upgrades it into a live grid in place, columns and rows read straight from the markup, and it survives htmx swaps.
-
about 2 min
Swap the import
A compatibility layer gives Lattice Grid the shape of another grid's API, so the constructor, the data and selection namespaces and the events keep working. Swap the import.
-
about 3 min
When the grid became the interface
Grids are sold to developers, so they are built for developers. Why Lattice Grid ships redaction, annotation and presentation tools to every user as standard.
-
about 4 min
A real spreadsheet, written by the grid
Not a CSV renamed to .xlsx. A real workbook with typed cells, a frozen header and your column widths, written in the browser with nothing added to your bundle.
-
about 3 min
Two ways to show a row's detail
A row that expands into a nested grid, or a pane beside the list where nothing moves. They solve different problems, and one config field switches between them.
-
about 4 min
Put the conversation next to the number
The question about a figure lives in a chat thread and the figure lives in a grid. Attach the discussion to the cell and both problems go away.
-
about 4 min
The view someone built on Monday is still there on Friday
Everybody rebuilds the same filter every morning. Name it once, and the queue opens the way each role needs it without anyone negotiating.
-
about 3 min
Hierarchies that survive real data
Every tree demo uses data that is already a tree. Yours will not be. Here is what happens to the orphan, the cycle and the missing level.
-
about 4 min
What did this row say a minute ago?
On a live grid the useful question is not what you did, it is what the data did. Drag the scrubber back and the cells that moved are marked.
-
about 4 min
Pause the feed without losing your place
An analyst reading a row while it moves under them will eventually read the wrong number. One button holds the grid still and counts what it is holding.
-
about 4 min
A grid that keeps up with the feed
Rows arriving faster than anyone can read them, a grid that stays scrollable while they do, and a rate measured in your browser rather than ours.
-
about 3 min
Put the actual numbers on the projector
Screenshots of a grid go stale between the export and the meeting. Present the grid itself, step saved views like slides, and answer the question in the room.
-
about 2 min
Share your screen without sharing the salaries
Every team has a spreadsheet they cannot put on a projector because of one column. Redaction hides the values and keeps the meeting working.
-
about 3 min
What changed since last week
The reconciliation everybody does with two exports and a lookup, done by the grid instead: what moved, what it was before, what arrived and what went.
-
about 4 min
Give the grid the whole window
A panel a few rows tall is a poor place to spend a morning. One control fills the screen with the grid, Escape puts it back, and your work comes with it.
-
about 4 min
Width is the harder problem
Everybody demos a long grid. The one that hurts is the wide one, where the row you are reading loses its name somewhere around column nineteen.
-
about 4 min
A million rows, timed on your machine
Every grid vendor has a benchmark number from a laptop you have never seen. The grid in this post times itself in your browser instead.
-
about 4 min
Types are not labels
In most grids a column type picks an alignment. Here it decides storage, comparison, parsing, formatting and the editor, from one word.
-
about 4 min
A column definition should read like a description
Forty flat properties per column is a config file nobody reads twice. Grouping them by concern, and naming the repeats, makes a column list readable.
-
about 3 min
Get going in two minutes
One script, one stylesheet, a div with a height and a list of columns. Sorting, filtering, resizing and reordering are already there.
-
about 3 min
One licence per domain, not per developer
A grid is installed once and touched by everybody afterwards. Pricing it per developer bills you for a fact about your org chart, not your product.
-
about 4 min
Why we built our own grid
Nobody sets out to write a data grid. We drew the comparison table first, and three shapes of problem kept sending us back to the whiteboard.
-
about 3 min
We built this for ourselves. Now you can buy it.
Lattice Grid ran inside our own platform against live customer data for years before it had a price. Here is what that means for you.