Abandonware of the web: do you know that there is an HTML tables API?
122 comments
·November 1, 2025Insanity
spinningarrow
I’ve been building sites since around 2000 and I’ve used HTML tables a lot (including for page layouts, remember those days?). There was a time when I thought I was fluent enough to not have to look up HTML or CSS docs for most things. But I don’t think I’ve ever actively used the DOM API that this article mentions so I learned something new today.
nunez
I feel like I used this when I built a red-light, green-light dashboard for Windows servers at a bank for my first job out of college (in 2009).
alentred
Thank you for confirming I am not... crazy, just old then. I was staring at the code for minutes, trying to spot something unusual that I missed. So, this really just about the `<table>` element, or do I actually not see something?
xg15
It's about the insertRow() and insertCell() methods and rows[] and cells[] fields on the table element, not the table itself.
eterm
I figured that was the normal way to interact with tables, what would people do otherwise?
paperpunk
It’s not about the table element, it’s about the API to construct and manipulate that element with a columns and rows interface which is largely superseded by general DOM manipulation.
littlestymaar
Exactly like how `getElementById` replaced the direct use of the id as a JavaScript identifier.
jcpst
Yep, didn’t realize this was unknown by enough web developers to warrant an article.
bryanrasmussen
I knew it existed but I figured it was only really useful for extremely data-table centric applications so I've never used it.
embedding-shape
I see new frontend developers using <div> for building buttons, and I've even seen people using <div> for doing titles! Us greybeards don't know how much apparent knowledge we're sitting on, it seems.
withinboredom
And spans for creating links…
null
jfengel
Is that bad?
Seems to me that we have redundant mechanisms for specifying semantics: tags and attributes (and classes as a specific attribute). Seems to me that tags are really just syntactic sugar for things like roles. Tables in particular are easily abused.
Of course I use the tag names, because they're idiomatic. But I feel like a newbie who identifies divs as the only true structure builder has a proper developer's intuition for separating presentation from content.
phkahler
HTML tables are cognitively if not officially deprecated these days. I made my 1996 resume in HTML using a table for layout and it was indistinguishable from the Word version when printed. Made by editing the HTML by hand too!
Tables are great. I don't doubt that CSS stuff is more capable, but the old ones are still useful.
xg15
I think the problem was that tables were always supposed to be for things that look like actual tables in the output - for that purpose they are not deprecated.
What is discouraged is using tables as invisible layout grids - and that was their primary de-facto usecase before CSS and grid layouts. But that had always been a hack, even though a necessary one.
fortyseven
Yep. Tables for tabular data are still on the menu.
dmd
Same. I use this all the time, have for decades. Had no idea other people didn’t.
zkmon
Just a catchy title. Not abandoned etc. This is the only API available to manipulate HTML table tags.
jazzypants
Most people use declarative frameworks to build tables, and you could just use `innerHTML` or `append` or any other imperative DOM API to work with tables.
moritzwarhier
appendChild, replaceChildren, etc work fine with tables?
prokopton
I’ve been doing ssr for so long I can’t fathom why you’d build a table using JS.
simonw
You knew about the .insertRow() and .insertCell() methods?
spiderfarmer
I made my first CRUD UI that didn't do full page refreshes with those methods.
tokioyoyo
Woah, it’s always weird to see how there’s modern web engineers that didn’t grow up during the era where entire layouts were built on tables. Not saying that it was good or bad, but just interesting.
skerit
Interesting, but the JavaScript examples hurt:
let table = [
['one','two','three'],
['four','five','six']
];
let b = document.body;
let t = document.createElement('table');
b.appendChild(t);
table.forEach((row,ri) => {
let r = t.insertRow(ri);
row.forEach((l,i) => {
let c = r.insertCell(i);
c.innerText = l;
})
});
Use full words for variable names!layer8
A bike-shedding thread on top as usual.
skerit
It's hard to read, especially in the lambdas.
It's a small critique, I'm sorry it got upvoted by other people.
bfkwlfkjf
Yeah I see this a lot on HN. I think people feel the need to make precise and accurate statements about things. I think a lot of them, if they'd deep breath and waited 30 minutes, they wouldn't comment.
embedding-shape
The internet is filled with pedantics, creeps and dogs posing as cats. The whole "take a breath" thing was early abandoned in favor of the now traditional "reply until the other party gives up" approach, which requires you to really dig into their messages and point out spelling mistakes, fallacies, and for programmers, variable names.
poisonborz
Code quality is not bike shedding.
Sharlin
It is, however, off topic and beside the point. And whether short names are a code quality issue is a rather contested and context-dependent topic.
nkrisc
Code quality of... an example snippet?
refulgentis
Usually I'd cosign, but I get it, after a similiar issue I had a couple days ago with a Rust article that was insanely frustrating to deal with.
It's a brain scramble because you can't just read in toto.
Well, you can literally, but, you don't feel like you grok it.
And when you take a second pass you gotta slow down and stop and parse "what's r here? is it relevant? oh rows?"
It's one of those things that's hard to describe because it doesn't sound like much if you got it. And this example is trivial, especially if you're not open to the idea its a problem (r/c = rows/columns) But it's nigh-impenetrable in other scenarios.
You feel like you're barely understanding something that you actually might grok completely.
embedding-shape
> It's one of those things that's hard to describe because it doesn't sound like much if you got it. And this example is trivial, especially if you're not open to the idea its a problem (r/c = rows/columns) But it's nigh-impenetrable in other scenarios.
I agree, it's highly context-specific.
In a small demo for a small blog post with basically no complexity? Go ahead, use 1 character variable names, it really isn't difficult.
In the 1000 long CUDA kernel where you barely understand what's going on even though you understand the concepts? I'd be favoring longer descriptive names than one letter names for sure.
Sharlin
It’s normal to use short names for things with short scopes.
foofoo12
Yes, and the reason for why that's OK is that the context is just few lines. But this is borderline due to the amount of variables.
In just 4 lines you have r, row, t, ri, l, i and c.
The full variables names are so short anyway that personally I'd write them out. Code does evolve and there's a risk of this suffering as a result.
Sharlin
That’s a fair point.
egorfine
> let b = document.body;
This one hurts the most. Save a few bytes for an ungodly amount of mental friction.
tbrownaw
It doesn't save any bytes, that variable is used once.
niek_pas
I was just about to comment the same. I’m sure people have a good reason for it (or at leafy _a_ reason), but single-letter variable names always struck me as optimizing for the wrong thing.
As someone who likes to program in Haskell, I feel this pain very strongly. :)
adamddev1
Strong BASIC memories. On the Apple IIe, anything after the first two characters of variable names was ignored.
bottd
Do you always feel this is the case? To me the go to single letter variables are very readable. Used so widely my eyes parse them like other symbols: =, &, +, etc.
alentred
My rule of thumb: only using single letter variables in one-liners (and never if it spills to another line), or for something that is conventionally represented as such. So for example:
```python
bar = [foo(e) for e in elements]
```
or, using `x`, `n`, `s` and similar when they represent just that, a generic variable with a number, string, etc. I think there is a Code Complete chapter about it.croes
In real ok, but in this short example it‘s pretty obvious what t,b, r and c mean
fsckboy
>Use full words for variable names!
that's like saying in spoken language "don't ever use pronouns, or even first or nicknames, use full given names"
groguzt
you are being intentionally dense, they are saying "don't use a single initial to identify someone, use their firstname instead"
shiandow
I think the short names aren't anywhere near as bad for readability as using (ri,i) as a table index.
If you're going to use short names at least make it clear which belong together. Especially don't use different lengths when things ought to be similar.
data.forEach((row,i) => row.forEach((ele,j) => ... ))jfengel
It's the lets that bother me. The point is elderly JS, and the entire operation is fundamentally imperative. But this code is brimming with opportunities to make mistakes. JS deserved its reputation.
phoronixrly
Looks to me like it's following the JS conventions... Jk, no such thing exists still!!
xg15
> Without having to re-render the whole table on each change.
That's nice, but isn't that what the standard DOM methods are already doing? Or does that API have any additional abilities?
Nevertheless, that's really cool and potentially saves a lot of tedious and error-prone DOM navigation.
zkmon
Abandoned? When? I still use this pretty much everywhere to create HTML tables. Do people use something else now?
moritzwarhier
Abandonware is a clickbait title insofar as it normally refers to licenses, not standards.
The idea of the author seems to be that this part of the DOM API that could benefit from backwards-compatible additions. So, by "abandoned", he hints at the headroom for building more table capabilities into the platform.
He compares it loosely to the form element API and the additions it received over the last decades.
In the case of tables, I could think of things such as a sorting, filtering API, but I can't tell whether that's what he means.
__jonas
People often use declarative UI frameworks such as React, Svelte etc. when they want to build things dynamically in JS like that now, so imperative DOM manipulation APIs have unsurprisingly become a little more niche.
littlestymaar
If by “Niche” you mean “not hype” then yes, but the PHP+jQuery combo is still very widely used in 2025 (likely more than React, given WordPress market share alone).
__jonas
Sure! But if you render server side (as with PHP), you'd likely just build up your table on the server rather than dynamically on the client, so you would also not use these imperative table element specific APIs.
Even if, for some reason, you were filling in the table content dynamically via jQuery, I think the fashion there was also to just pass in whole HTML markup snippets as strings to be injected into the DOM, so you'd also more likely use plain <tr> elements than this table-specific API, same as with a 'hype' framework of now.
jckahn
Yes, React
embedding-shape
Why would it matter what library you use? I'm using React, I do <table> whenever I need to display tabular data, React or no React as no impact on when I'd use <table>.
iammrpayments
Just make sure to pass a subscriber to useSyncExternalStore if you decide to venture outside React and use HTMLTable.insertRow, you see react is really smart and won’t let you use this piece of outdated code without punishing you with side effects.
Thanks Vercel & Meta for protecting us.
zkmon
And what does that use internally to manage tables? Just because there is layer between you and the API, it doesn't mean API is abandoned.
__jonas
Are you implying that when doing DOM reconciliation, React uses these table-specific insertRow/insertCell APIs for adding and removing elements in tables instead of the regular DOM element APIs it would use for all other elements? I would be surprised if that's the case.
moritzwarhier
React is as orthogonal to DOM manipulation API as it is to letting the browser render tables from HTML.
iammrpayments
Why would anyone use this outdated code over useInsertRow() and useTableColumnEffect()?
StrauXX
> Without having to re-render the whole table on each change.
Not quite sure what the author means by that. Re-rendering pnly happens when the current task queue elemt has been processed. Never while JS is running (aside from webworker and the like). I would honestly be surprised if this API had much (if any) performance benefits over createElement.
_the_inflator
Sure!
And there is way more to it.
This kind of code was common and also the starting point of every modern language innovation we have today in JavaScript - even TypeScript, and maybe any modern web development on the server as well.
Tables were the only way to create browser independent layouts dynamically. Or put another way: adding interactivity to websites. And simply because hacking is fun and browsers were experimenting with APIs accessible by JavaScript.
CSS was still bleeding from ACID tests, Netscape was forgotten, Mozilla build Phoenix out of the ashes of the bursting bubble and called their effort Firefox.
In Germany there was and still is the infamous selfHTML project. I remember vividly reading and testing Stefans Münz tutorials on this topic. The content is untouched, only the layout changed, so go back in time for more table fun:
https://wiki.selfhtml.org/wiki/Beispiel:JS-Anwendung-Tabelle...
https://wiki.selfhtml.org/wiki/JavaScript/Tutorials/Tabellen...
It was pretty common to have large one file websites: php and html with css and javascript mixed.
There was no git, no VisualStudio Code, Claude Sonnet - no, Notepad and later Notepad++
(Even the DOOM guys had no version control system in the early stages.)
For me John Resig shines out here. Epic genius behind jQuery. The source code was pure magic, and his book "Secrets of the JavaScript Ninja" is for me the all time climax in programming excellence.
If you never utilised the prototype property, you will never understand any of the most basic structures and inner workings JavaScript has to this day and why Classes are "syntactical sugar" for functions and nothing else.
Function.toString in combination with New Function made me enter 10 matrices in parallel at the time. What a revelation. :D
Nicholas Zakas comes close with his seminal Web Development book, in which he featured every Browser API available at the time with examples on roughly 1000 pages. To this day, exercising most of it and understanding the DOM and Windows object was the best investment ever, because and this fact 15 years later paved the way for the success of a financial SaaS platform. Lost wisdom, not covered by any modern framework like Angular or ReacJS.
smusamashah
I used this for a small tool I was making to see stable Diffusion images in a table to compare images on different set of parameters, had lots of rows and columns. I needed to regenerate tables quickly, I vaguely remember this API being much slower than making rows/cells via strings. The reason I found was that each call using this API updates DOM and with string it's all in one go (or something similar).
zX41ZdbW
I was using it just half a year ago, after either reading MDN or reading what AI suggested. Which means, this API is not obscure and not forgotten. Using `rows` and `cells` is very convenient for keyboard navigation across table cells.
https://github.com/ClickHouse/ClickHouse/blob/master/program...
conception
The worst thing on the modern web is people using divs for table data. What do you mean this table isn’t sortable? M365 Admin is the worst offender I’ve come across on this. Just terrible table implementations on almost every page.
mr_toad
Is there a term for the opposite of cargo culting? Where everyone avoids something, but no one remembers why? Because that’s basically where HTML tables have ended up.
embedding-shape
I think this is something like a "delayed cargo culting", or "cargo culting based on outdated facts". I think it's basically the same as the hypothesis from the "Monkey Ladder Experiment", where monkeys got punished when trying to get a banana, and eventually all the monkeys were replaced with monkeys that didn't realize why the banana was off-limits, yet persisted in trying to "help" other monkeys trying to prevent them from getting the banana.
I'm not sure if I read that that specific experiment was debunked or not, but it certainly sounds familiar to how some developer trends get propagated even though the ground truth as changed.
psadri
The trouble is not populating it. The trouble is that tables, even though structured semantically, give you absolutely no functionality. There are no search, filter, sort, or selection features that you get.
est
please rediscover html form API
stared
It is similar as with buttons (https://news.ycombinator.com/item?id=45774182).
Not sure when it was (10-15 years ago), but at some point everything became <div>s. So, instead of semantic markup, HTML became a UI toolbox.
macintux
I think it was inevitable. Most of the funded content on the web is marketing/sales-driven, and companies paying for marketing content want it to be displayed in a specific way.
It’d be interesting to have a parallel DocBook web for technical content, where consumers of that content could apply their own styles to render it in a way that’s best for them.
jazzypants
I mean, you can just remove all the user agent styles and then <button> is just as stylable as <div>.
macintux
Why would marketing want to pay for the extra (and to their mind entirely pointless) work required to capture semantics?
(I’m not saying I like the world we live in, but I don’t see a likely alternative.)
Phew, this post single handedly made me feel old this morning. I started dabbling with the web just over 20 years ago but have mainly been working on the backend the past 10-15 years. I had no clue that nowadays programmers don’t know about this, so I assume it’s supplanted by modern frameworks or modern JS/CSS