DEV Community

Muhammet Kaya
Muhammet Kaya

Posted on AI-assisted

One engine, two render layers: how I built the same data grid for Angular and React

A data grid is mostly not rendering. Sorting, filtering, grouping, virtualization windows, range
selection, keyboard navigation, clipboard, undo — none of it needs a framework. Yet most grids are
written inside one, and the "other framework" version is a wrapper that feels foreign.

I wanted the opposite for OGE UI: one engine with no framework
in it, and a render layer per framework that is native to it. This post is what that looks like in
practice and what it cost.

The split

The engine is plain TypeScript. It owns the data source, the filter and sort pipeline, group
trees, the virtualization math, selection and range state, and the keyboard maps. It knows nothing
about Angular or React and has no runtime dependencies.

The Angular layer exposes that state as signals. Every input, output and piece of grid state is
a signal; there are no decorators and no Zone.js. Components are OnPush and mark exactly what
changed.

The React layer is real components with props, callbacks and controlled state. It subscribes
to the engine through useSyncExternalStore, so concurrent rendering and StrictMode behave.

Both layers share one stylesheet and one set of CSS design tokens.

What you get from doing it this way

  • Behaviour cannot drift. A sorting bug is fixed once. A parity check in CI compares the two API tables member by member and fails the build when one side gains something the other lacks.
  • Tests are cheap where the logic is. Engine specs need no component, no template and no framework test bed.
  • Each framework feels like itself. Angular users get template type checking on every column; React users get render props instead of a template DSL.

What it cost

  • Two render layers is two sets of components to write, document and test. The engine removes the logic duplication, not the work.
  • Deciding what belongs in the engine is a judgment call every time. Focus management and popup positioning ended up in a shared, framework-free "behavior" package; templating never will.
  • Idioms do not map one to one. An Angular TemplateRef becomes a React render prop, and those deliberate differences have to be written down or they look like bugs.

Does it perform?

On 100,000 rows, production build, median of five cold runs on a laptop i7:

Measurement Angular React
First render 197 ms 168 ms
Filter: equals 124 ms 131 ms
Sort: number column 261 ms 223 ms
Scroll 47 fps 60 fps

The Angular scroll number is the one I am not satisfied with yet. The script that produced the
table is in the repo, and the benchmarks page explains exactly
what is timed, so you can check it on your own machine.

What is free

The grid is MIT, including the parts that are often a paid tier: grouping with summaries, styled
Excel and PDF export, cell ranges with clipboard paste and fill handle, master-detail and
server-side data operations. So are the tree list, 25+ editors, forms and the rich-text editor.

The project is open-core: pivot, charts, scheduler, gantt, kanban, BPMN and a spreadsheet viewer
are commercial. I would rather say that in the article than have you find it in a licence file.

Try it

If you have built a multi-framework library, I would like to hear where you drew the engine
boundary — it is the decision I have changed my mind about most often.





Enter fullscreen mode Exit fullscreen mode

Top comments (0)