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.
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;
})
});
The variable naming convention used here could be improved for clarity. I prefer appending `El` to variables that hold DOM elements, as it makes identifiers like `tableEl` clearer and helps avoid ambiguity between variables such as `table` and `row`. Also, the variable named `table` does _not_ actually represent a table element; it would be more accurate to name it `data` or `tableData` to better reflect its purpose.
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
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).
I feel like IndexedDB is becoming this abandonware as well. There are so many ways where this (IMO rather badly designed) API can be improved but the standards committee seems completely uninterested. Even things like adding BigInt as primative is unimplemented.
I fear this will be even worse now that we have the origin File System API and people can bring their own database engines (like web-assambled SQLite). But for those of us that are striving towards smaller download sizes this is a disaster.
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.
> 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.
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:
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.
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.
The depreciation of marquee and blink wasn't necessary; it's web developer's choice whether to use these and the visitor's choice whether to be repulsed. Marquee should have been improved for use as ticker elements for specialized application. The depreciation of nobr misses the point - the alternative is more complex. Hope the standard continues to keep the legacy elements: small, i, em, hr... etc.
A lot of people here are clearly not reading the article.
It’s not about the <table> element itself—we hope everyone knows about tables—but rather about the table-specific DOM interface, including things like HTMLTableElement.prototype.insertRow() and HTMLTableRowElement.prototype.insertCell() as alternatives to the generic DOM techniques like Document.prototype.createElement() and Node.prototype.appendChild().
These are handy if you’re hand-writing your DOM interactions, but libraries that construct and maintain DOM trees (e.g. React, Svelte, Vue) will never use them, and that’s the direction everything has headed, so in practice they’ve fallen into near-complete disuse.
They match HTML syntax in another important way: HTML tables have thead/tbody/tfoot section elements, but you can mostly skip writing them in HTML syntax because it’ll imply <tbody> open and close tags. Likewise in this interface, if you have a thead/tbody/tfoot element you can call .insertRow() on it, but you can also call .insertRow() on the table, and it’ll put it in the last tbody, creating one if necessary. Meanwhile, I presume in React/Svelte/Vue/whatever you must write out your tbody manually.
I’ve definitely used at least .insertRow, .insertCell, .createTHead, .rows and .cells in the last five years in no-library throwaway/demo scripts where I was generating tables.
—⁂—
Concerning the specific example given, here’s what I find a clearer code style, using for instead of forEach, using better variable names, and omitting the index argument to insertRow/insertCell which was quite unnecessary and only confused matters (the author doesn’t seem to have realised it’s optional):
let data = [
['one','two','three'],
['four','five','six']
];
let table = document.createElement('table');
for (const row of data) {
let tr = table.insertRow();
for (const value of row) {
tr.insertCell().innerText = value;
}
}
document.body.append(table);
This is a great reminder that the Eternal September still exists and perhaps mercifully appears to be affecting those with at least some technical exposure.
24 comments
[ 2.4 ms ] story [ 34.3 ms ] threadI remember doing this 25 years ago, but I assume (and hope) it's a huge minority who do this today?
https://archive.ph/APbi8
https://github.com/ClickHouse/ClickHouse/blob/master/program...
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.
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.
Topic is reminiscent of a submission from yesterday about XSLT:
https://news.ycombinator.com/item?id=45779261
I fear this will be even worse now that we have the origin File System API and people can bring their own database engines (like web-assambled SQLite). But for those of us that are striving towards smaller download sizes this is a disaster.
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.
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.
It’s not about the <table> element itself—we hope everyone knows about tables—but rather about the table-specific DOM interface, including things like HTMLTableElement.prototype.insertRow() and HTMLTableRowElement.prototype.insertCell() as alternatives to the generic DOM techniques like Document.prototype.createElement() and Node.prototype.appendChild().
These are handy if you’re hand-writing your DOM interactions, but libraries that construct and maintain DOM trees (e.g. React, Svelte, Vue) will never use them, and that’s the direction everything has headed, so in practice they’ve fallen into near-complete disuse.
They match HTML syntax in another important way: HTML tables have thead/tbody/tfoot section elements, but you can mostly skip writing them in HTML syntax because it’ll imply <tbody> open and close tags. Likewise in this interface, if you have a thead/tbody/tfoot element you can call .insertRow() on it, but you can also call .insertRow() on the table, and it’ll put it in the last tbody, creating one if necessary. Meanwhile, I presume in React/Svelte/Vue/whatever you must write out your tbody manually.
I’ve definitely used at least .insertRow, .insertCell, .createTHead, .rows and .cells in the last five years in no-library throwaway/demo scripts where I was generating tables.
—⁂—
Concerning the specific example given, here’s what I find a clearer code style, using for instead of forEach, using better variable names, and omitting the index argument to insertRow/insertCell which was quite unnecessary and only confused matters (the author doesn’t seem to have realised it’s optional):
https://en.wikipedia.org/wiki/Eternal_September