What actually went wrong
The handler did the obvious thing: mark the clicked row as selected, then re-render the
table so the highlight shows up. Re-rendering meant building every row again. That
alone is O(N) work for an O(1) change, which is wasteful but
survivable.
The bigger cost was the second mistake: each row's size was read back out of the layout engine immediately after it was written. Writing invalidates layout; reading forces it to be recomputed on the spot. Do both in a loop and the browser recalculates the whole document once per row — a full layout pass per row, for one click.
Drag rows up and run it again. The red bar should grow with the row count — roughly quadratically, since the per-row cost also rises as the document gets bigger. The green bar should barely move: it does the same two class changes whether there are 64 rows or 2048.
An honest note on the numbers. The only timings on this page are the ones your browser measures when you press Run; they depend on your machine and engine. What the demo shows is the shape: an O(1) change priced as O(N), amplified by synchronous layout reads, and a fix that is subtraction rather than cleverness.