Exploring the "Is this a real or fake table?" algorithm in desktop browsers
There are a lot of websites out there that, unfortunately, use the <table>
HTML element as a styling tool. This poses a problem to users of assistive technology, as there is now a lot of incorrect semantic information in the page.
To mitigate this issue when creating the accessibility tree, browsers try to guess when a <table>
is being used for purely styling purposes. If they guess that a <table>
might not really be a table, that information is then hinted to assistive technology. For example, here is a <table>
that no major browser on desktop will expose as a table - you can take any screen reader to the linked codepen to verify for yourself.
I thought it would be interesting to look at this guessing algorithm in more detail. We will look at some minimal codepens of <tables>
that start out as purely stylistic layout tables, and then tweak them just barely enough to make browsers think they are real data tables. 🙂
Definitions
- Accessibility tree
- A tree data structure that represents a graphical user interface, commonly consumed by assistive technology (although they are not the only consumers).
- Assistive technology
- Software or hardware that disabled people use to improve their quality of life.
- Layout table
- A table that is only used for styling, and not for showing tabular data.
- Data table
- Any table that isn't a layout table.
Notes on testing
Only if you want to know the gritty technical details.
A note on how I tested
- On Windows, I will look for the
layout-guess
attribute on the<table's>
IAccessible2 node using the dump tree utility. If a node has this attribute set to true, it's a layout table, otherwise it's a data table. - On Mac, I will look to see if the
<table>
is exposed as a table in the accessibility tree using the Accessibility Inspector. If it's not, it's a layout table, otherwise it's a data table. - On Linux:
- For Chrome and Edge, I will look to see if the
<table>
is exposed as a table in the accessibility tree using the dump tree utility. If it's not, it's a layout table, otherwise it's a data table. - For Firefox, I will look for the
layout-guess
attribute on the<table's>
AT-SPI node using Accerciser. If a node has this attribute set to true, it's a layout table, otherwise it's a data table.
- For Chrome and Edge, I will look to see if the
At the time of this writing, I am testing with versions:
- Chrome Version 114.0.5735.90
- Edge Version 114.0.1823.37
- Firefox Version 113.0.2
- Safari Version 16.4 (18615.1.26.11.23)
Finally, for simplicity's sake, I will not list browser + platform combinations as each individual browser's results don't seem to change with the desktop platform. I will just list the results of each browser, and you can assume those results are true for Windows, Mac, and Linux.
A note if you want to test
- On Chrome and Edge, you can use the Accessibility Inspector in the developer tools. Layout tables will be explicitly called out as layout tables here.
- On Firefox, you can use:
- NVDA on Windows and use NVDA table shortcuts to see if it detects a table.
- Voiceover on Mac and use Voiceover table shortcuts to see if it detects a table.
- Orca on Linux and use Orca table shortcuts to see if it detects a table.
- On Safari, you can use Voiceover and use Voiceover table shortcuts to see if it detects a table.
Finally, if you plan on modifying the HTML to experiment, you should use the CodePen editor instead of modifying the HTML directly through the developer tools.
I'm seeing that browsers don't necessarily update the guess of whether a table is a layout table or a data table if the table is modified after being rendered, so edits through the developer tools won't always work. Edits in the codepen work as they refresh the embedded <iframe>
.
Determining table-ness via HTML
All major browsers will attempt to search for certain table-specific semantic elements. If it finds any, it will abort the algorithm early and just declare the table to be a data table. Browsers seem to agree that tables with a <caption>
, <thead>
, or <tfoot>
are all data tables.
Codepen: Determining table-ness via the presence of HTML elements
Determining table-ness via the number of rows
All major browsers will attempt to count the number of rows that a table has, and if it has sufficiently many it will be declared a data table. Chrome, Edge, Firefox, and Safari all agree that a table with at least 20 rows is a data table.
As soon as we make the table have 19 rows, however, every browser except Firefox considers the table a layout table.
Thoughts on Firefox behavior
I was a little bit confused at first on why Firefox thought the extremely minimal table with 19 rows was a data table. Especially since Firefox seems to do a similar row count check that other browsers use, from reading the code.
My immediate guess as to why (without examining with a debugger) is that Firefox seems to assume every table is a data table until proven otherwise, while other browsers assume that a table is a layout table until proven otherwise. Again, this is just speculation from reading the code, and I would need to use a debugger to verify my hypothesis.
Codepen: Determining table-ness via the number of rows
Determining table-ness via the CSS background-color
of table rows
The incorporation of CSS in this guessing algorithm is very interesting to me.
All four browsers seem to agree that a table with alternating background-colors
on its rows is a data table, as long as the table has more than two rows. Firefox is the only browser that does not enforce a minimum of three rows when checking that the rows have alternating backgrounds.
Codepen: Determining table-ness via the CSS background-color of table rows
Determining table-ness via the CSS background-color
of table cells
Chrome, Edge, and Safari all check if any kind of background-color
CSS property is defined on the table cell. If this is true for at least half of the cells in the table, then it becomes a data table. However, note that the background-color
has to be explicitly defined on the <td>
- defining the background-color
on the <tr>
won't work.
Firefox does not seem to employ this heuristic at all.
Codepen: Determining table-ness via the CSS background-color of table cells
Determining table-ness via the CSS border
of table cells
All major browsers do checks on the border of table cells to help determine whether something is a data table or not.
Chrome, Edge, and Safari check to see if any side of the table cell has a border. If this is true for at least half of the cells in the table, those browsers expose the table as a data table.
Firefox does it slightly differently - it only checks the first table cell, and checks if it has a border on all sides. If so, Firefox exposes the table as a data table.
Codepen: Determining table-ness via the CSS border of table cells
Source code
Reading the source code for this algorithm was really helpful in constructing these minimal codepens.
If you're curious, here is where you can walk through the algorithm's logic yourself in Chromium.
Note how you can opt out of this entire guessing logic by just manually setting role="table"
on the element. (Of course, don't use ARIA unless you need to)
If you can't access Chromium code search
As for the other browsers, I'm not exactly sure where the logic is since I haven't debugged those browsers and am not as familiar with their codebases, but I can give a fairly likely guess from reading the code:
There is some logic I didn't cover - for example, Firefox seems to do checks on how wide the <table>
is relative to the entire page. I also left out mobile platforms in order to simplify this post, as the mobile behavior doesn't seem as consistent at an initial glance and would require some nuance. I encourage you to read the code yourself if you want to learn more!
Finally, here is some more code speculation/archaeology that I did while doing research for this post:
- Probably where NVDA checks to see if a table is a layout table or a data table
- Probably where Orca checks to see if a table is a layout table or a data table
Again, there might be some context I'm missing, but I think it's cool to see how everything connects together.