Width is the harder problem
The grid you were shown when you were choosing was long. A hundred thousand rows, five columns, scrolling beautifully. The grid you have to build is a retail estate with thirty-eight fields on every site, and by the time the finance team has scrolled far enough right to see EBITDA they have no idea which store they are looking at.
Long is the demo. Wide is the ticket.
Height is a solved problem. Width usually is not.
Row virtualisation is table stakes and has been for a decade: render the rows in the window, recycle them as the window moves. Almost everything does it, and almost everything stops there, because vertical is where the impressive number lives.
Horizontally, the naive implementation puts every cell of every rendered row in the DOM. Forty columns times forty visible rows is sixteen hundred elements recreated on every scroll and restyled on every theme change, and it is why wide grids feel gritty in a way long ones do not: the cost is paid on the axis nobody optimised.
This grid renders the horizontal window too. Above thirty columns, which is the default and is spelled out in the demo’s configuration, the body paints only the columns you can see plus the pinned ones. On our two hundred column demo that works out at seventeen cells in the DOM for each row out of two hundred and one columns. The readout under the grid above counts the same thing in your browser, by asking your own DOM rather than by us telling you: scroll sideways and the count does not move.
The header is deliberately not culled. Every heading cell stays in the DOM because the header is where the resize handles, the menus and the filter row live, and a heading that appeared only when you were already looking at it would break every one of them.
Pinned edges that leave the middle reachable
Pinning is the obvious fix for the finance team who cannot remember which store they are on, and it is the place most implementations quietly break. Both edges of the grid above are pinned: the site code and the store name on the left, the EBITDA figure and the risk flag on the right. Between them are thirty-four columns of estate detail nobody keeps in their head.
The failure to look for is a centre column that becomes unreachable. When the horizontal scroll range is computed from the total width rather than the width of the scrolling region, the last few centre columns end up permanently underneath the right-hand pinned block, and the only way to read them is to unpin something. We have checked this one specifically on the grid above, because it is the bug this class of implementation ships most often: scroll all the way right and the audit score, the last centre column, comes out from behind the pinned pair and is fully readable.
Which columns live at the edges is not our decision either. Open the menu on any heading and Pin column is in it, so the analyst who wants the manager’s name beside the site code rather than the risk flag can have that, and the grid re-flows around the choice.
What wide grids cost you if the grid will not do it
The workaround every team reaches for is to stop showing the columns. You build a column chooser, then a set of presets because the chooser is tedious, then a way to save the presets, then a way to share them, and now four days of the sprint went to rebuilding a feature because scrolling sideways was unpleasant. The columns panel and the saved views in the rail on the left of that grid exist so nobody on your team writes any of that.
The other workaround is worse: split the screen into three tabs, and accept that nobody can compare a number in tab one against a number in tab three.
Thirty-eight columns and twenty thousand sites is not a large grid. It is an ordinary internal screen, and it should not need a project.
See it at two hundred columns or read how pinning and layout are configured.