Shauna Keating
HCI 530 Advanced Accessibility
April 19, 2026
For a better experience, visit: https://shkeating.github.io/a11y-examples/tables/common-failures/
Common Failures
Table 1: Tables for layout
Section titled “Table 1: Tables for layout”- WCAG Failure Technique F49
- Uses an HTML layout table that does not make sense when linearized.
- WCAG Failure Technique F46
- Uses semantic table elements (
summary,caption) in a layout table.
- Uses semantic table elements (
| The quick brown fox | jumps over the | lazy dog. |
| Accessibility is | a fundamental right | for all users. |
| Never use tables | just to position | elements on a screen. |
| Screen readers will | read this left to right | and it will sound awful. |
<table class="layout-table" summary="This table is used to format the page layout"> <caption>Page Layout Structure</caption> <tr> <td>The quick brown fox</td> <td>jumps over the</td> <td>lazy dog.</td> </tr> <tr> <td>Accessibility is</td> <td>a fundamental right</td> <td>for all users.</td> </tr> <tr> <td>Never use tables</td> <td>just to position</td> <td>elements on a screen.</td> </tr> <tr> <td>Screen readers will</td> <td>read this left to right</td> <td>and it will sound awful.</td> </tr></table>Table 2: Bad Data Table
Section titled “Table 2: Bad Data Table”- General SC 1.3.1 Failures
- leaves the
captionelement blank. thtable headers are empty.
- leaves the
- WCAG Failure Technique F90
- incorrectly associates table header and content via the
headerandidattributes.$85,000cell associated to non existent id
- incorrectly associates table header and content via the
- WCAG Failure Technique F91
- not correctly marking up table headers (e.g., using a standard
tdelement with CSS classes to visually fake a header for “Employee Name” instead of using an actualthelement)
- not correctly marking up table headers (e.g., using a standard
- WCAG Failure Technique F92
- using
role="presentation"on a table that contains real tabular data, which completely strips the table semantics and hides the data grid from screen readers
- using
thmissingscopeattributes.thelements should usescope="col"orscope="row"to clearly identify their relationship to the data.- combines separate pieces of data into a single column, listing assigned equipment for phone and laptop in same assigned equipment column.
- uses
brelements to create visual line breaks inside a cell to fake a row (in the cells under Assigned Equipment). If a user resizes the text, the data will no longer align correctly. - for the rows using “zebra striping” to distinguish even and odd rows, uses colors with a poor contrast ratio between the text and the background.
| Employee Name | Department | Salary | Assigned Equipment | |
|---|---|---|---|---|
| 1 | John Doe | Engineering | $85,000 | Laptop: Dell XPS 15 |
| 2 | Jane Smith | Marketing | $72,000 | Laptop: MacBook Air |
| 3 | Bob Johnson | IT Support | $65,000 | Desktop: HP Envy |
| 4 | Alice Williams | Human Resources | $78,000 | Laptop: Lenovo ThinkPad |
| 5 | Charlie Brown | Sales | $60,000 | Laptop: Surface Pro |
<table role="presentation" class="bad-zebra"> <caption></caption> <tr> <th></th> <td class="fake-header">Employee Name</td> <th id="hdr-dept">Department</th> <th id="hdr-salary">Salary</th> <th id="hdr-assets">Assigned Equipment</th> </tr> <tr> <td>1</td> <td>John Doe</td> <td>Engineering</td> <td headers="hdr-bonus">$85,000</td> <td> Laptop: Dell XPS 15<br> Monitor: LG 27"<br> Phone: iPhone 13 </td> </tr> <tr> <td>2</td> <td>Jane Smith</td> <td>Marketing</td> <td headers="broken-id-reference">$72,000</td> <td> Laptop: MacBook Air<br> Tablet: iPad Pro </td> </tr> <tr> <td>3</td> <td>Bob Johnson</td> <td>IT Support</td> <td headers="hdr-bonus">$65,000</td> <td> Desktop: HP Envy<br> Monitor: Dual Dell 24"<br> Phone: Yealink Desk Phone </td> </tr> <tr> <td>4</td> <td>Alice Williams</td> <td>Human Resources</td> <td headers="broken-id-reference">$78,000</td> <td> Laptop: Lenovo ThinkPad<br> Phone: Google Pixel 7 </td> </tr> <tr> <td>5</td> <td>Charlie Brown</td> <td>Sales</td> <td headers="hdr-bonus">$60,000</td> <td> Laptop: Surface Pro<br> Tablet: iPad Mini<br> Phone: Samsung Galaxy S23 </td> </tr></table>Table 3: Div “Table”
Section titled “Table 3: Div “Table””- uses
divelements and CSS to visually recreate a “table” without the appropriate semantic HTML structure.
Product
Price
Wireless Mouse
$25.00
Mechanical Keyboard
$80.00
USB-C Hub
$45.00
Ergonomic Office Chair
$250.00
27-inch 4K Monitor
$320.00
<div class="div-table"> <div class="div-row"> <div class="div-header">Product</div> <div class="div-header">Price</div> </div> <div class="div-row"> <div class="div-cell">Wireless Mouse</div> <div class="div-cell">$25.00</div> </div> <div class="div-row"> <div class="div-cell">Mechanical Keyboard</div> <div class="div-cell">$80.00</div> </div> <div class="div-row"> <div class="div-cell">USB-C Hub</div> <div class="div-cell">$45.00</div> </div> <div class="div-row"> <div class="div-cell">Ergonomic Office Chair</div> <div class="div-cell">$250.00</div> </div> <div class="div-row"> <div class="div-cell">27-inch 4K Monitor</div> <div class="div-cell">$320.00</div> </div></div>Table 4: Responsive CSS & Tabindex Mistakes
Section titled “Table 4: Responsive CSS & Tabindex Mistakes”- Uses
display: block;in the CSS. While visually stacking the data for mobile, this CSS override removes the table semantics in the browser’s accessibility tree. Screen readers treat it like a generic list of text. - Uses
tabindex="0"on every cell, forcing keyboard users toTabthrough all of the data instead of using their typical table navigation controls - WCAG Failure Technique F87
- Inserts non-decorative content (“Status: ”) using CSS
::beforepseudo-elements. This data might not be read by all screen readers and cannot be easily highlighted or copied by users.
- Inserts non-decorative content (“Status: ”) using CSS
| Server Name | Uptime | Health |
|---|---|---|
| Alpha-01 | 99.9% | Online |
| Beta-02 | 85.4% | Degraded |
<div class="block-table"> <table> <caption>Server Status Grid</caption> <tr> <th scope="col">Server Name</th> <th scope="col">Uptime</th> <th scope="col">Health</th> </tr> <tr> <td tabindex="0">Alpha-01</td> <td tabindex="0">99.9%</td> <td tabindex="0">Online</td> </tr> <tr> <td tabindex="0">Beta-02</td> <td tabindex="0">85.4%</td> <td tabindex="0">Degraded</td> </tr> </table></div>Table 5: Going Against Best Practices
Section titled “Table 5: Going Against Best Practices”- does not include a semantic
captionelement, relying instead on a standard heading (h3) positioned above the table. Screen reader menus will list this table as “unnamed.” - misuses the
scopeattribute by applyingscope="col"to row headers andscope="row"to column headers. - uses an empty
tdelement to create visual indentation/spacing, creating confusing “dead zones” for keyboard and screen reader navigation.
Quarterly Sales Goals
| Q1 | Q2 | |
|---|---|---|
| North America | $500,000 | $550,000 |
| New York Office | $150,000 | |
| Europe | $420,000 | $480,000 |
<h3>Quarterly Sales Goals</h3><table> <tr> <th></th> <th scope="row">Q1</th> <th scope="row">Q2</th> </tr> <tr> <th scope="col">North America</th> <td>$500,000</td> <td>$550,000</td> </tr> <tr> <td style="border: none; background: #fff;"></td> <td class="fake-header">New York Office</td> <td>$150,000</td> </tr> <tr> <th scope="col">Europe</th> <td>$420,000</td> <td>$480,000</td> </tr></table>