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);
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.
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.
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.
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.
That's because the DOM is mostly used as a render target instead of a semantic document.
I think semantic HTML is a great idea but it's kind of jaded to expect it at this point.
It also doesn't help that semantic elements have styling. That right there gives people good reason to use a neutral container as a baseline. In fact I would go as far as to say that having both div and span is a bad design decision. They are just aliases for css `display` values.
That is one reason. Another reason is everybody’s way of organizing content is different. There would need to be an infinite set of semantic tags to really make it work.
I've been writing HTML for at least 20 years professionally and this has absolutely not been my experience. Yes, I've encountered some people using divs for everything but in the vast majority of cases people have used semantically correct HTML, at least when it comes to buttons.
> Yes, I've encountered some people using divs for everything but in the vast majority of cases people have used semantically correct HTML, at least when it comes to buttons.
I dunno; ISTR that the materializecss library used `<a>` for buttons.
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.
Because not everyone has useful eyeballs. Some people are blind. The amount of extra work you have to do to make a div faithfully act like a button is far more than simply resetting some styles.
It's more challenging to encourage correct implementation of semantics than implemention of visuals; which is a great reason for using the element that was designed for this use case.
I've literally never had a marketing person tell me whether I should use a <button> or <div>. Let's not pretend things like using the wrong semantic elements is anyone else's fault but lazy or inexperienced developers.
These days it's a moot point anyway, because everyone is using things like tailwind which provide a full reset for things like default buttons, so there really is no excuse.
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).
> 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.
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.
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.
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).
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.
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>.
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.
> 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.
Huh? Why'd you involve state in this or any imperative code? You render the rows/columns as you'd render any other DOM elements in React, pass in the data as props and iterate on it, create children and pass them to render.
Yes, your point? Anyone who spend 15 minutes learning about React learns that you don't manipulate the DOM directly, you let the rendering engine handle that for you.
Or just skip all of the newly released stuff and use React as it was originally made, like me and many others still do. Never suffer from having to debug "useEffect" because we literally never use it. You don't have to use the newest and shiniest toys, especially not those with footguns.
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.
The funny thing is the insertRow/insertCell API just call into DOM manipulation functions like appendChild internally, they just provide some syntactic sugar around things like managing the rows/cells array. It's all the same
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.
Javascript arrays have functions for all of that, so if you use something like React and renders your table from data arrays then it's all pretty trivial. I guess the point is that if you have to use JS to do those manipulations, then at some point it's going to be easier to just the React(/Vue/Svelte/etc) approach than manipulating the table yourself using the API described in the article.
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.
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;
})
});
I understand the frustration (probably no one feels it more than we do, because it's our job to help discussion stay meaningful). But please don't respond by posting like this.
It takes time for the contrarian dynamic to work itself out (https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...), and once that happens, the original problem subsides but and the secondary problem (shallow objection to the objection) sticks out like a sore thumb.
It's usually enough to downvote (or, in egregious cases) flag a post that shouldn't be at the top. In really egregious cases, emailing hn@ycombinator.com is also a fine idea.
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.
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.
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.
> 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.
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. :)
It is also a math thing. most(if not all) constructions intended for mathematical consumption have some of the most miserable naming I have ever seen. I think it comes down to two things. when I am feeling less charitable it is that naming things is hard. so they don't bother. And when more charitable it is that they are optimizing for quick mental manipulation of a familiar machine. This tends toward the smallest variable names you can get away with, tons of implied context and compressed symbology. Of course this leaves the rest of us struggling, not with the concept but the way it is presented.
I like to joke, "you think programmers are bad at naming thing, you should see the mathematicians, programmers are infants before the infernal naming sense of the common mathematician".
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.
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.
Don’t use ‘i’ (looks like 1), use ‘j1’, etc - helps set you up if you need a nested loop someday. Of course, at that point better naming would probably be best.
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.
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.
HTMLTableElement.prototype.rows actually just returns a HTMLCollection, so same as document.forms, or document.getElementsByClassName. HTMLCollection implements Symbol.iterator as you would expect.
My personal stance on short variable names is that they are fine as long as their scope is very limited, which is the case here. Rather, the "crime" to me is an overuse of rather pointless variables as the majority of them were only used once.
Disclaimer: I have not tested the code and I only write JavaScript once every few years and when I do I am unhappy about it.
This is not an improvement. Having named variables for things is good actually. They will need to be declared again immediately once you want to modify the code. insertCell(i).innerText = c is a nonsense statement, it should be 2 lines for the 2 operations
I disagree, but maybe it is a cultural thing for those of us that are more used to functional styles of programming? I was taught method chaining as a style by a seasoned JavaScript and Ruby programmer myself and I do not find the semantics confusing. "Create X with Y set to 17 and Z to 4711" can be either on one or three lines to me, as long as the method calls are clear and short enough.
As for variables, I (again personally) find it taxing to have many variables in scope, so I do net see their presence as a universal good. If we instead simply use expressions, then there is no need to concern yourself with whether the variable will come into play later on. Thus, I think it increases clarity and favour that over the ease of future modification argument you propose (heck, I would argue that you get better diffs even if you force the variable declaration into a future modification).
As for bikeshedding this piece of code further, if I steal some ideas from chrismorgan [1] and embedding-shape [2] who appear to be way more seasoned JavaScript programmers than me:
const $t = document.createElement('table');
for (const r of
[
['one', 'two', 'three'],
['four', 'five', 'six' ],
]) {
const $r = $t.insertRow();
for (const e of r)
$r.insertCell().innerText = e;
};
document.body.append($t);
This is now rather minimal and the logic is easy (for me) to follow as the scopes are minimal and namespace uncluttered. It was a rather fun little exercise for a language I am not overly familiar with and I learned a few tricks and perspectives.
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.
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.
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’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.
> Phew, this post single handedly made me feel old this morning.
I hear you!
For me though, it made me feel old for a different reason
I had first developed webapps in the late 90s (96 onwards) using cgi-bin, perl, etc. My first webapp, done for money, was something similar to MRTG.
At some point in the last almost-30-years) I had actually used this API! I have, however, forgotten all about it and was only reminded of it with this post.
So, yeah, I feel old because I can legitimately say to many modern web-devs that "I've forgotten more about web dev than you you currently know" :-)
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?
Sorry I - also - am one of those old timers who don't understand this because the shown code is all I've ever used for creating table. So, what is this "standard DOM API" if I may ask? Could you post a code example?
You can use document.createElement and document.appendChild to create every last <th>, <tr>, and <td> if you want. Those functions are not specific to tables, unlike the one mentioned in the blog post. They can be used to create any elements and place them in the DOM. But if you know what you are doing you can get a perfectly fine table out of that. (Not that you should.)
Yeah, that was what I was thinking of. I knew those as the essential APIs to modify the DOM without a full re-parse. And you can use them on table/th/tr/td nodes just like on any other node.
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.
I remember there being posts that explicitly discouraged using IDs directly, but I'm not sure of tge reasons anymore. Maybe browser incompatibilities or unclear scoping and confusion with other variables?
It works everywhere (it’s now specified in https://html.spec.whatwg.org/multipage/nav-history-apis.html...), but it’s brittle. It can break by adding colliding properties to window deliberately or by accidental global leak (… including things like setting in dev tools), by browser defining new globals, by some 'name' attribute conflict.
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.
In 2004 I was at a company that dedicated a team of people to rebuilding a bunch of tables (lots of financial data) in to styled divs because... "tables are depreciated". The fact that they couldn't pronounce or understand the word "deprecated" should have been enough of a clue to ignore this person, but they were the 'lead' on the web team, and... had been there longer than other people. Obviously they must know what they're talking about. Weeks later after having converted dozens of spreadsheets to divs (instead of just using tables) they were 'done', but it was a tremendous waste of time that ignored all the semantics of tables. I was asked to 'help out' on that project to meet the deadline and refused, citing that it was not just stupid, but a big waste of time and against web semantics.
"table" was never deprecated in HTML at all, but was discouraged for general layout (we were aware of this even in the early 2000s). But for representing tabular data - like... data in rows/columns from spreadsheets (with column headers and such)... HTML tables were absolutely the right (only?) way to present this.
I recently discovered our frontend widget library draws an SVG to implement Radio instead of using <input type="radio">. I was looking at it because they forgot to add a "disabled" attribute.
Best case I'm hoping it's because they were required to get an exact design, but they really should have pushed back on that one if so.
And for the ones that remember to implement middle-mouse click to open new tabs, forgets that one can also do CTRL+click to open in new tab, or vice-versa.
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.
As long as you think about semantics and accessibility and does the extra work to add those things, then not really.
But why add those extra things when we already get those for free by doing <h1> and then customizing the style? Everything you'd need to manually add, automatically works fine then, so seems like a no-brainer to avoid putting more work on your table.
div-as-button/link leaves a lot of default interaction behaviour on the table. You'll need to handle all the keyboard interactions yourself, all the accessibility markup, etc.
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.
Yea, but that's pretty much irrelevant as long as the effect is exactly the same. Which brings us back to the point of the article: seeing this and feeling inspired to imagine interface extensions that go beyond syntax sugar.
I was replying to the wrong comment, because I was responding to this:
> I still use this pretty much everywhere to create HTML tables. Do people use something else now?
Regarding React: what would be the benefit for using this old syntax sugar in its vDOM implementation?
Page reflow is not an issue for vDOM as it batches such updates anyway?
And using syntax sugar without benefits in the DOM reconciliation would be pointless.
React also doesn't locate form input elements using document.forms.[name]?.[name] because... why should they?
Just because they can...
Regarding the creation of tables, the most common way to do it would be... parsing initial document's HTML?!
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.
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.
> What is discouraged is using tables as invisible layout grids - and that was their primary de-facto usecase before CSS and grid layouts.
After too.
I've seen enough "Introduction to CSS"s filled with caveats and hemming & hawing to know that it's all to be avoided when+if possible. I know, I know, there's a whole wide wonderful world out there full of aligns and borders and containers and insets and margins and masks and offsets and paddings and positions oh my. Bleccch..
Tables are probably still useful for layout in HTML emails (for advertising). I haven't had to work with HTML emails in probably 20 years, but I doubt much has changed about what is and isn't allowed in HTML emails.
Back in the early to mid 2000's, making your site "table free" while still working on IE6 was seen as a badge of masochistic pride.
Doing table-free multi-column layouts involved doing crazy “float: left/right + padding + margin” with an heavy sprinkle of IE6 clearfix hacks to work right. I mean eventually people dialed in the correct incantations to make table-free designs work for IE6 but it was never quite as straightforward or reliable as a good old fashioned table. Many megajoules of energy were wasted on webform drama between the pragmatic "fuck you, tables just work and I have shit to ship" webdev and the more academic "tables break the semantic web and aren't needed, use CSS." crew.
Like most things, the "tables are evil" mantra was taken too far and people started to use floated divs (or <li/>’s or <span/>’s or whatever) for shit that actually was tablular data! (I was guilty of this!).
And like most things, a lot of the drama went away when IE6 finally went away. People who weren't around back then simply cannot understand exactly how much IE6 held back modern web design. You could almost count on half your time being spent making shit work for IE6, despite the ever decreasing amount of traffic it got. I'm pretty sure I almost cried the day Google slapped a "IE6 will no longer be supported" on it's site.... the second they did that, my site got the exact same banner. Fuck IE6. The amount of costs that absolute pile of shit browser caused the industry exceeded the GDP of entire nations.
Anyway.... back to adding weird activex shit in my CSS so IE6 can support alpha-blended PNGs....
It's worth checking who the author is... Cristian's not exactly new to the game. I think he's being humble he doesn't know something despite his experience.
I've been working on a little SPA that manipulates tabular data and allows the user to insert rows. This is exactly the API I've been using. Like a lot of other commenters it never occurred to me that people wouldn't know this API exists.
Aside: I started with Perl CGI scripts, then ColdFusion, and finally Classic ASP back in the 90s. I had a chuckle a couple years ago dealing with a younger developer who was shocked that and oldster like me was up on new-fangled SSR patterns.
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.
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.
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.
Probably because I first learned programming with JavaScript and very early started using jQuery, but I've always used prefixed `$` to indicate "This is a DOM element" (started doing this once jQuery stopped being so popular). So the example would be something like this for me:
let table = [
['one','two','three'],
['four','five','six']
];
let $body = document.body;
let $table = document.createElement('table');
$body.appendChild($table);
Always felt it worked out short and sweet, and as long as you're not refactoring a jQuery codebase, seems to work out well in practice.
How about displaying data in rows and columns in a accessible and easily styled way, without having to rely on JS and your own CSS to replicate a table? How exactly would you do that with HTML and CSS without using tables? Using flex and grid for those purposes don't make much sense unless you care about design above all else.
<table> just gives you so many good defaults (semantic structure, accessibility, column styling, column alignment, keyboard navigation) for free compared to using CSS to create your own table, that I'm not sure why you wouldn't use <table> for tabular data.
Of course, if you need masonry, card grids and so on it makes sense, do actual layouting with layouting tools. But thankfully <table> hasn't died just yet, it's still better than CSS for many use cases.
I think this is the gist of it. Tables were abused as general spaced 1D, and 2D styling components. Introducing proper general spacial styling components means we don't need to extend tables beyond their original purpose, but doesn't mean we shouldn't use them for that purpose!
This implies that you were considering -- for a split second -- making a 90s style table based website layout, using the Tables API? ;) I might have to try that now...
Young folk don't understand just how wildly different IE5 was to the Netscape or the Mozilla browser. Or just how bad Javascript was when it started to be used on the internet.
I've lived through and seen the evolution. For all the shit the JS community takes for constantly revving frameworks, it's 1000x easier to make a website that looks the same regardless of browser due to a lot of these frameworks and browsers themselves evolving.
It's not that long ago that tables were the only reliable layout tool for HTML emails (mostly due to Outlook supporting only very limited subset of CSS).
How about displaying data in rows and columns, like records in a database? Or have you forgotten SQL, because you retrieve JSON from your 1000 NoSQL microservices?
Using only CSS for tabular row and column data is just as wrong as using tables for layout. There are legit reasons for using <table> today that can't be replicated by CSS. Namely, CSS doesn't confer the same semantic meaning into markup that <table> does.
I agree with many other replies here, specifically about accessibility. Once I learned how to use a screen reader, it was eye-opening. So many web applications are utterly broken for users with assistive technologies.
Tables built with flex and grid absolutely can be made accessible with WAI-ARIA, but native table elements are harder to mess up.
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):
I feel like frameworks have taken over and so few people know the foundations anymore. Thank you.
I still remember reading a news article on C|net about the addition of the <table> element.
Yeah, I'm old.
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...
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.
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.
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.
I would guess that people became so afraid of being accused of using tables for layout that they don't use them at all.
It's still cargo culting
Using HTML Tables doesn’t just make your data sortable
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.
That's because the DOM is mostly used as a render target instead of a semantic document.
I think semantic HTML is a great idea but it's kind of jaded to expect it at this point.
It also doesn't help that semantic elements have styling. That right there gives people good reason to use a neutral container as a baseline. In fact I would go as far as to say that having both div and span is a bad design decision. They are just aliases for css `display` values.
The semantic web never took off because companies don't want to make their content easy to scrape.
Just look at how they salivate for WASM where everything is closed up and inaccessible, including a11y.
That is one reason. Another reason is everybody’s way of organizing content is different. There would need to be an infinite set of semantic tags to really make it work.
I've been writing HTML for at least 20 years professionally and this has absolutely not been my experience. Yes, I've encountered some people using divs for everything but in the vast majority of cases people have used semantically correct HTML, at least when it comes to buttons.
> Yes, I've encountered some people using divs for everything but in the vast majority of cases people have used semantically correct HTML, at least when it comes to buttons.
I dunno; ISTR that the materializecss library used `<a>` for buttons.
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.
I mean, you can just remove all the user agent styles and then <button> is just as stylable as <div>.
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.)
Because not everyone has useful eyeballs. Some people are blind. The amount of extra work you have to do to make a div faithfully act like a button is far more than simply resetting some styles.
It seems evident to me that semantics are more challenging to define than visuals; it's not the CSS that's the problem.
It's more challenging to encourage correct implementation of semantics than implemention of visuals; which is a great reason for using the element that was designed for this use case.
I've literally never had a marketing person tell me whether I should use a <button> or <div>. Let's not pretend things like using the wrong semantic elements is anyone else's fault but lazy or inexperienced developers.
These days it's a moot point anyway, because everyone is using things like tailwind which provide a full reset for things like default buttons, so there really is no excuse.
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).
> 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.
> 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.
I quickly looked into the webkit code and there's probably absolutely no performance benefit, the same logic should be running behind the scenes
please rediscover html form API
Abandoned? When? I still use this pretty much everywhere to create HTML tables. Do people use something else now?
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.
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.
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).
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.
JS hasn't been invented to render on the client side but to allow interactivity.
Yes, React
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>.
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.
> 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.
Huh? Why'd you involve state in this or any imperative code? You render the rows/columns as you'd render any other DOM elements in React, pass in the data as props and iterate on it, create children and pass them to render.
InsertRow updates the live DOM and React just wholesale replaces it. It’s a masterstroke footgun.
Yes, your point? Anyone who spend 15 minutes learning about React learns that you don't manipulate the DOM directly, you let the rendering engine handle that for you.
Yes that’s why of instead of learning the standard apis, you have to spend 15 months learning how to debug useEffect
Or just skip all of the newly released stuff and use React as it was originally made, like me and many others still do. Never suffer from having to debug "useEffect" because we literally never use it. You don't have to use the newest and shiniest toys, especially not those with footguns.
React is as orthogonal to DOM manipulation API as it is to letting the browser render tables from HTML.
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.
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.
The funny thing is the insertRow/insertCell API just call into DOM manipulation functions like appendChild internally, they just provide some syntactic sugar around things like managing the rows/cells array. It's all the same
https://github.com/WebKit/WebKit/blob/28fa568972a4d34d867948...
Why would anyone use this outdated code over useInsertRow() and useTableColumnEffect()?
What are those and where are they in standard Javascript / DOM API?
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.
Compared to what? What gives you all that, and what prevents you from having it with tables?
Javascript arrays have functions for all of that, so if you use something like React and renders your table from data arrays then it's all pretty trivial. I guess the point is that if you have to use JS to do those manipulations, then at some point it's going to be easier to just the React(/Vue/Svelte/etc) approach than manipulating the table yourself using the API described in the article.
Frameworks that make development easy are inherently inefficient. If performance is priority, then you better sort it yourself.
countless plugins for use in countless frameworks. We should have all that built-in by now. like we finally have a functioning date picker.
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.
Interesting, but the JavaScript examples hurt:
Use full words for variable names!A bike-shedding thread on top as usual.
I understand the frustration (probably no one feels it more than we do, because it's our job to help discussion stay meaningful). But please don't respond by posting like this.
It takes time for the contrarian dynamic to work itself out (https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...), and once that happens, the original problem subsides but and the secondary problem (shallow objection to the objection) sticks out like a sore thumb.
It's usually enough to downvote (or, in egregious cases) flag a post that shouldn't be at the top. In really egregious cases, emailing hn@ycombinator.com is also a fine idea.
From the guidelines: "Please don't sneer, including at the rest of the community." - https://news.ycombinator.com/newsguidelines.html
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.
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.
Code quality is not bike shedding.
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.
Code quality of... an example snippet?
Especially
especially now that the example is gonna end up in some LLM somewhere and folks will just copy pasta.
It's hard to read, especially in the lambdas.
It's a small critique, I'm sorry it got upvoted by other people.
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.
> 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.
It’s normal to use short names for things with short scopes.
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.
That’s a fair point.
rowIndex isn’t that short.
We might be able to use rowIx? Let's discuss it on the next Monday standup. Everyone will need to have an opinion, max 5 minutes per person.
shortness is in the eye of the beholder… program with spring framework long enough and rowIndex sounds like abbreviation. :)
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. :)
It is also a math thing. most(if not all) constructions intended for mathematical consumption have some of the most miserable naming I have ever seen. I think it comes down to two things. when I am feeling less charitable it is that naming things is hard. so they don't bother. And when more charitable it is that they are optimizing for quick mental manipulation of a familiar machine. This tends toward the smallest variable names you can get away with, tons of implied context and compressed symbology. Of course this leaves the rest of us struggling, not with the concept but the way it is presented.
I like to joke, "you think programmers are bad at naming thing, you should see the mathematicians, programmers are infants before the infernal naming sense of the common mathematician".
Strong BASIC memories. On the Apple IIe, anything after the first two characters of variable names was ignored.
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.
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:
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.Yeah, I'm not GP, but my exceptions to this rule are `i` for "iterator" in `for` loops and `e` for "event" in event listeners.
Don’t use ‘i’ (looks like 1), use ‘j1’, etc - helps set you up if you need a nested loop someday. Of course, at that point better naming would probably be best.
In real ok, but in this short example it‘s pretty obvious what t,b, r and c mean
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.
> let b = document.body;
This one hurts the most. Save a few bytes for an ungodly amount of mental friction.
It doesn't save any bytes, that variable is used once.
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.
>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"
you are being intentionally dense, they are saying "don't use a single initial to identify someone, use their firstname instead"
Personally I'd make everything const instead of let and use for of instead of forEach, but it's like 10 lines of code it doesn't really matter.
Are you sure this old API does the right thing with for…of?
It's only used to iterate the array
Oops, right, I confused the variables.
Should work just fine:
HTMLTableElement.prototype.rows actually just returns a HTMLCollection, so same as document.forms, or document.getElementsByClassName. HTMLCollection implements Symbol.iterator as you would expect.https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableEl...
Really? The variable name lengths? Not that the code is clearer as:
My personal stance on short variable names is that they are fine as long as their scope is very limited, which is the case here. Rather, the "crime" to me is an overuse of rather pointless variables as the majority of them were only used once.Disclaimer: I have not tested the code and I only write JavaScript once every few years and when I do I am unhappy about it.
This is not an improvement. Having named variables for things is good actually. They will need to be declared again immediately once you want to modify the code. insertCell(i).innerText = c is a nonsense statement, it should be 2 lines for the 2 operations
I disagree, but maybe it is a cultural thing for those of us that are more used to functional styles of programming? I was taught method chaining as a style by a seasoned JavaScript and Ruby programmer myself and I do not find the semantics confusing. "Create X with Y set to 17 and Z to 4711" can be either on one or three lines to me, as long as the method calls are clear and short enough.
As for variables, I (again personally) find it taxing to have many variables in scope, so I do net see their presence as a universal good. If we instead simply use expressions, then there is no need to concern yourself with whether the variable will come into play later on. Thus, I think it increases clarity and favour that over the ease of future modification argument you propose (heck, I would argue that you get better diffs even if you force the variable declaration into a future modification).
As for bikeshedding this piece of code further, if I steal some ideas from chrismorgan [1] and embedding-shape [2] who appear to be way more seasoned JavaScript programmers than me:
This is now rather minimal and the logic is easy (for me) to follow as the scopes are minimal and namespace uncluttered. It was a rather fun little exercise for a language I am not overly familiar with and I learned a few tricks and perspectives.[1]: https://news.ycombinator.com/item?id=45782938
[2]: https://news.ycombinator.com/item?id=45781591
Looks like your code inserts a new row for every cell.
Cheers! Fixed.
Looks to me like it's following the JS conventions... Jk, no such thing exists still!!
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.
I’m curious what changes the author would like to see to the API
intermittent loading errors (503 Service Unavailable)
https://archive.ph/APbi8
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.
Will Google remove this API then if it’s abandoned?
Topic is reminiscent of a submission from yesterday about XSLT:
https://news.ycombinator.com/item?id=45779261
XSLT requires hundreds of thousands (maybe millions?) of lines of security-sensitive code. That's why it's proposed for removal.
I doubt that's true for .insertCell() and .insertRow().
> That way they’d finally get the status as data structures and not a hack to layout content on the web.
I remember doing this 25 years ago, but I assume (and hope) it's a huge minority who do this today?
cough view-source:https://news.ycombinator.com/item?id=45781293 cough
Hey Chris :-)
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’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.
Surprised, as we used this a lot around 2005, when IE6 was still dominant.
If was much simpler to build tables in javascript with this rather than using document.createElement.
Perhaps this was one of those things that you just had to know about, or be working on data heavy web apps.
> Phew, this post single handedly made me feel old this morning.
I hear you!
For me though, it made me feel old for a different reason
I had first developed webapps in the late 90s (96 onwards) using cgi-bin, perl, etc. My first webapp, done for money, was something similar to MRTG.
At some point in the last almost-30-years) I had actually used this API! I have, however, forgotten all about it and was only reminded of it with this post.
So, yeah, I feel old because I can legitimately say to many modern web-devs that "I've forgotten more about web dev than you you currently know" :-)
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?
It's about the insertRow() and insertCell() methods and rows[] and cells[] fields on the table element, not the table itself.
I figured that was the normal way to interact with tables, what would people do otherwise?
Using the standard DOM APIs or - if they don't care about anything - innerHTML, I suppose.
Sorry I - also - am one of those old timers who don't understand this because the shown code is all I've ever used for creating table. So, what is this "standard DOM API" if I may ask? Could you post a code example?
You can use document.createElement and document.appendChild to create every last <th>, <tr>, and <td> if you want. Those functions are not specific to tables, unlike the one mentioned in the blog post. They can be used to create any elements and place them in the DOM. But if you know what you are doing you can get a perfectly fine table out of that. (Not that you should.)
Yeah, that was what I was thinking of. I knew those as the essential APIs to modify the DOM without a full re-parse. And you can use them on table/th/tr/td nodes just like on any other node.
createElement(‘tr’) and table.appendChild(row)
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.
Exactly like how `getElementById` replaced the direct use of the id as a JavaScript identifier.
I remember there being posts that explicitly discouraged using IDs directly, but I'm not sure of tge reasons anymore. Maybe browser incompatibilities or unclear scoping and confusion with other variables?
It was either Mozilla (Netscape, I think) or IE that it didn’t work on for the longest time.
I think that was a native IE API that Mozilla had to add support for, as well as document.all (Netscape used document.layers).
It works everywhere (it’s now specified in https://html.spec.whatwg.org/multipage/nav-history-apis.html...), but it’s brittle. It can break by adding colliding properties to window deliberately or by accidental global leak (… including things like setting in dev tools), by browser defining new globals, by some 'name' attribute conflict.
Yep, didn’t realize this was unknown by enough web developers to warrant an article.
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.
In 2004 I was at a company that dedicated a team of people to rebuilding a bunch of tables (lots of financial data) in to styled divs because... "tables are depreciated". The fact that they couldn't pronounce or understand the word "deprecated" should have been enough of a clue to ignore this person, but they were the 'lead' on the web team, and... had been there longer than other people. Obviously they must know what they're talking about. Weeks later after having converted dozens of spreadsheets to divs (instead of just using tables) they were 'done', but it was a tremendous waste of time that ignored all the semantics of tables. I was asked to 'help out' on that project to meet the deadline and refused, citing that it was not just stupid, but a big waste of time and against web semantics.
"table" was never deprecated in HTML at all, but was discouraged for general layout (we were aware of this even in the early 2000s). But for representing tabular data - like... data in rows/columns from spreadsheets (with column headers and such)... HTML tables were absolutely the right (only?) way to present this.
I was at that company less than a year...
And spans for creating links…
I recently discovered our frontend widget library draws an SVG to implement Radio instead of using <input type="radio">. I was looking at it because they forgot to add a "disabled" attribute.
Best case I'm hoping it's because they were required to get an exact design, but they really should have pushed back on that one if so.
Sounds like they either don't care about accessibility or like wasting money comprehensively reinventing things.
Thereby forgetting that some people like to open links in a new tab.
And for the ones that remember to implement middle-mouse click to open new tabs, forgets that one can also do CTRL+click to open in new tab, or vice-versa.
Just use <a> please :)
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.
> Is that bad?
As long as you think about semantics and accessibility and does the extra work to add those things, then not really.
But why add those extra things when we already get those for free by doing <h1> and then customizing the style? Everything you'd need to manually add, automatically works fine then, so seems like a no-brainer to avoid putting more work on your table.
div-as-button/link leaves a lot of default interaction behaviour on the table. You'll need to handle all the keyboard interactions yourself, all the accessibility markup, etc.
I knew it existed but I figured it was only really useful for extremely data-table centric applications so I've never used it.
Same. I use this all the time, have for decades. Had no idea other people didn’t.
Just a catchy title. Not abandoned etc. This is the only API available to manipulate HTML table tags.
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.
Declarative frameworks build on the imperative DOM API.
They don't use .insertRow() and .insertCell(). Try searching the React codebase for those.
Yea, but that's pretty much irrelevant as long as the effect is exactly the same. Which brings us back to the point of the article: seeing this and feeling inspired to imagine interface extensions that go beyond syntax sugar.
I was replying to the wrong comment, because I was responding to this:
> I still use this pretty much everywhere to create HTML tables. Do people use something else now?
Regarding React: what would be the benefit for using this old syntax sugar in its vDOM implementation?
Page reflow is not an issue for vDOM as it batches such updates anyway?
And using syntax sugar without benefits in the DOM reconciliation would be pointless.
React also doesn't locate form input elements using document.forms.[name]?.[name] because... why should they?
Just because they can...
Regarding the creation of tables, the most common way to do it would be... parsing initial document's HTML?!
What do they use?
appendChild() and the like.
And, not a single one of the declarative frameworks use the HTMLTableElement API!
So how they do they talk to the browser to add a row to the table? Do you know of any API other than DOM used for this?
They use createElement instead of the table-specific API.
appendChild, replaceChildren, etc work fine with tables?
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.
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.
> What is discouraged is using tables as invisible layout grids - and that was their primary de-facto usecase before CSS and grid layouts.
After too.
I've seen enough "Introduction to CSS"s filled with caveats and hemming & hawing to know that it's all to be avoided when+if possible. I know, I know, there's a whole wide wonderful world out there full of aligns and borders and containers and insets and margins and masks and offsets and paddings and positions oh my. Bleccch..
How was it a hack?
Hack implies brittleness. Using tables for layout was just fine for all but the most ideologically pure pedants.
Tables are probably still useful for layout in HTML emails (for advertising). I haven't had to work with HTML emails in probably 20 years, but I doubt much has changed about what is and isn't allowed in HTML emails.
Yep. Tables for tabular data are still on the menu.
> HTML tables are cognitively if not officially deprecated these days.
According to who?
Back in the early to mid 2000's, making your site "table free" while still working on IE6 was seen as a badge of masochistic pride.
Doing table-free multi-column layouts involved doing crazy “float: left/right + padding + margin” with an heavy sprinkle of IE6 clearfix hacks to work right. I mean eventually people dialed in the correct incantations to make table-free designs work for IE6 but it was never quite as straightforward or reliable as a good old fashioned table. Many megajoules of energy were wasted on webform drama between the pragmatic "fuck you, tables just work and I have shit to ship" webdev and the more academic "tables break the semantic web and aren't needed, use CSS." crew.
Like most things, the "tables are evil" mantra was taken too far and people started to use floated divs (or <li/>’s or <span/>’s or whatever) for shit that actually was tablular data! (I was guilty of this!).
And like most things, a lot of the drama went away when IE6 finally went away. People who weren't around back then simply cannot understand exactly how much IE6 held back modern web design. You could almost count on half your time being spent making shit work for IE6, despite the ever decreasing amount of traffic it got. I'm pretty sure I almost cried the day Google slapped a "IE6 will no longer be supported" on it's site.... the second they did that, my site got the exact same banner. Fuck IE6. The amount of costs that absolute pile of shit browser caused the industry exceeded the GDP of entire nations.
Anyway.... back to adding weird activex shit in my CSS so IE6 can support alpha-blended PNGs....
I remember those days. It was simpler to use tables for layout than to use early CSS for quite a while.
It's worth checking who the author is... Cristian's not exactly new to the game. I think he's being humble he doesn't know something despite his experience.
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).
I’ve been doing ssr for so long I can’t fathom why you’d build a table using JS.
I've been working on a little SPA that manipulates tabular data and allows the user to insert rows. This is exactly the API I've been using. Like a lot of other commenters it never occurred to me that people wouldn't know this API exists.
Aside: I started with Perl CGI scripts, then ColdFusion, and finally Classic ASP back in the 90s. I had a chuckle a couple years ago dealing with a younger developer who was shocked that and oldster like me was up on new-fangled SSR patterns.
You knew about the .insertRow() and .insertCell() methods?
I made my first CRUD UI that didn't do full page refreshes with those methods.
I think most of us did the ol `$el.appendChild(document.createElement('tr'))` dance rather than using those, at least I did during the 00s for sure.
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.
I remember doing image maps, splitting large images up into pieces, placing them in table cells and adding links to each cell as a poor man's GUI
I did this with OCR text. The OCR software output bounding boxes which I converted into client side image maps. The company wanted to patent it.
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.
https://en.wikipedia.org/wiki/Eternal_September
And the release of the iPhone created another, larger wave.
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.
Probably because I first learned programming with JavaScript and very early started using jQuery, but I've always used prefixed `$` to indicate "This is a DOM element" (started doing this once jQuery stopped being so popular). So the example would be something like this for me:
Always felt it worked out short and sweet, and as long as you're not refactoring a jQuery codebase, seems to work out well in practice.The author didn’t know the <TABLE> tag existed ???
Tables died (thankfully) to make room for flex and grid. I can't see any use case for them at all anymore.
How about displaying data in rows and columns in a accessible and easily styled way, without having to rely on JS and your own CSS to replicate a table? How exactly would you do that with HTML and CSS without using tables? Using flex and grid for those purposes don't make much sense unless you care about design above all else.
<table> just gives you so many good defaults (semantic structure, accessibility, column styling, column alignment, keyboard navigation) for free compared to using CSS to create your own table, that I'm not sure why you wouldn't use <table> for tabular data.
Of course, if you need masonry, card grids and so on it makes sense, do actual layouting with layouting tools. But thankfully <table> hasn't died just yet, it's still better than CSS for many use cases.
Nothing about flex or grids requires JS. That's entirely CSS.
I personally disagree. When data is semantically a table, not just a “table-looking” layout, I would rather use the table tag.
I think this is the gist of it. Tables were abused as general spaced 1D, and 2D styling components. Introducing proper general spacial styling components means we don't need to extend tables beyond their original purpose, but doesn't mean we shouldn't use them for that purpose!
The use case for a table is to present data.
This implies that you were considering -- for a split second -- making a 90s style table based website layout, using the Tables API? ;) I might have to try that now...
Tabular data? Tables have a purpose, it's just that people misused them for layout purposes.
To be fair, we did that when there wasn’t much choice for laying out web pages other than using tables. I was there!
Especially in ways that worked cross browser.
Young folk don't understand just how wildly different IE5 was to the Netscape or the Mozilla browser. Or just how bad Javascript was when it started to be used on the internet.
I've lived through and seen the evolution. For all the shit the JS community takes for constantly revving frameworks, it's 1000x easier to make a website that looks the same regardless of browser due to a lot of these frameworks and browsers themselves evolving.
It's not that long ago that tables were the only reliable layout tool for HTML emails (mostly due to Outlook supporting only very limited subset of CSS).
How about displaying data in rows and columns, like records in a database? Or have you forgotten SQL, because you retrieve JSON from your 1000 NoSQL microservices?
Rows and columns are exactly what grid was added to CSS for.
Using only CSS for tabular row and column data is just as wrong as using tables for layout. There are legit reasons for using <table> today that can't be replicated by CSS. Namely, CSS doesn't confer the same semantic meaning into markup that <table> does.
Compare https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/...
with https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_la...
I'd hate to hear that on a screen reader.
They’re probably still quite useful for displaying tabular data - there’s also semantics involved, it’s not primarily just a layout mechanism.
I agree with many other replies here, specifically about accessibility. Once I learned how to use a screen reader, it was eye-opening. So many web applications are utterly broken for users with assistive technologies.
Tables built with flex and grid absolutely can be made accessible with WAI-ARIA, but native table elements are harder to mess up.