CINXE.COM
WebAIM: Creating Accessible Tables - Data Tables
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>WebAIM: Creating Accessible Tables - Data Tables</title> <link rel="shortcut icon" href="/media/favicon.ico"> <link rel="home" href="/"> <link rel="search" href="/search/"> <link rel="alternate" href="https://webaim.org/blog/feed" type="application/rss+xml" title="WebAIM Blog"> <script async src="https://www.googletagmanager.com/gtag/js?id=G-Y41PF8WV9X"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-Y41PF8WV9X'); </script> <link href="/styles/main.css" rel="stylesheet" type="text/css"> <link href="/styles/print.css" rel="stylesheet" type="text/css" media="print"> <script src="/media/scripts/jquery.js"></script> <script src="/media/scripts/main.js"></script> <link href='https://fonts.googleapis.com/css?family=Roboto:400' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Kameron:400,700' rel='stylesheet' type='text/css'> <link href="/styles/documents.css?ver=2" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700" rel="stylesheet"> <!--[if lt IE 9]> <script type="text/javascript" src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> </head> <body> <div id="headcontainer" class="clearfix" style="background-image: url(/media/banners/articles.jpg)"> <header> <div id="skiptocontent"><a href="#maincontent">skip to main content</a></div> <h2><a href="/"><img src="/media/logo.png" width="315" height="83" alt="WebAIM - Web Accessibility In Mind"></a></h2> <nav> <h2 class="hidden">Main Navigation</h2> <ul> <li><a href="/services/">Services</a></li> <li class="current"><a href="/articles/">Articles</a></li> <li><a href="/resources/">Resources</a></li> <li><a href="/projects/">Projects</a></li> <li><a href="/community/">Community</a></li> </ul> </nav> <div id="search"> <form method="get" role="search" action="/search/" id="sitesearch"> <p class="search"><span><label for="q">Search:</label> <input type="text" name="q" id="q"><input type="image" src="/media/template/search.svg" alt="Submit Search"></span></p> </form> <p class="intro"><a href="/intro">Introduction to Web Accessibility</a></p> <p class="training"><a href="/services/training">WebAIM Training</a></p> </div> </header> </div> <main id="maincontainer" class="clearfix"> <article id="maincontent"> <h1>Creating Accessible Tables<br><span class="subtitle">Data Tables</span></h1> <p id="breadcrumbs"><span class="hidden">You are here: </span><a href="/">Home</a> > <a href="/articles/">Articles</a> > <a href="./">Tables</a> > Page 2: Data Tables</p> <nav role="navigation"> <h2>Article Contents</h2> <ol> <li>Page 1:<a href="./"> Layout Tables</a></li> <li class="currentpage">Page 2: Data Tables <ol> <li><a href="#up">Marking Up Data Tables</a></li> <li><a href="#caption">Table Captions</a></li> <li><a href="#th">Identify Row and Column Headers</a></li> <li><a href="#headers">Associate the Data Cells with the Appropriate Headers</a></li> <li><a href="#prop">Use Proportional Sizing, Rather than Absolute Sizing</a></li> <li><a href="#other">Other table markup</a></li> </ol> </li> </ol> </nav> <div class="section" id="up"> <h2>Marking Up Data Tables</h2> <p>The purpose of data tables is to present tabular information in a grid, or matrix, and to have column or rows that show the meaning of the information in the grid. Sighted users can visually scan a table. They can quickly make visual associations between data in the table and their appropriate row and/or column headers. Someone that cannot see the table cannot make these visual associations, so proper markup must be used to make a programmatic association between elements within the table. When the proper HTML markup is in place, users of screen readers can navigate through data tables one cell at a time, and they will hear the column and row headers spoken to them.</p> </div> <div class="section" id="caption"> <h2>Table Captions</h2> <p>Data tables very often have brief descriptive text before or after the table that indicates the content of that table. This text should be associated to its respective table using the <code><caption></code> element. The <code><caption></code> element must be the first thing after the opening <code><table></code> tag.</p> <code class="programlisting"> <table><br> <strong><caption></strong>Shelly's Daughters<strong></caption><br> </strong>... </code> <p>While it is not necessary for each table to have a caption, a caption is generally very helpful. If present, it should be associated to the table using the <code><caption></code> element.</p> </div> <div class="section" id="th"> <h2>Identify Row and Column Headers</h2> <p>A critical step toward creating an accessible data table is to designate row and/or column headers. In the markup, the <code><td></code> element is used for table data cells and the <code><th></code> element is used for table header cells. Going back to our original data table example, the column headers for this table are <em>Name</em>, <em>Age</em>, and <em>Birthday</em>. The row headers are <em>Jackie</em> and <em>Beth</em>. Also note the associated caption.</p> <table> <caption>Shelly's Daughters</caption> <tr> <th scope="col">Name</th> <th scope="col">Age</th> <th scope="col">Birthday</th> </tr> <tr> <th scope="row">Jackie</th> <td>5</td> <td>April 5</td> </tr> <tr> <th scope="row">Beth</th> <td>8</td> <td>January 14</td> </tr> </table> <p>Table headers should never be empty. This is particularly of concern for the top-left cell of some tables</p> </div> <div class="section" id="headers"> <h2>Associate the Data Cells with the Appropriate Headers</h2> <p>Now that we've created headers, we need to associate the data cells with the appropriate headers.</p> <div class="section" id="scope"> <h3>The <code>scope</code> attribute</h3> <p>The scope attribute identifies whether a table header is a column header or a row header. Here is the markup for the table, using the <code>scope</code> attribute:</p> <code class="programlisting"> <table><br> <caption>Shelly's Daughters</caption><br><br> <tr><br> <th <b>scope="col"</b>>Name</th><br> <th <b>scope="col"</b>>Age</th><br> <th <b>scope="col"</b>>Birthday</th><br> </tr><br><br> <tr><br> <th <b>scope="row"</b>>Jackie</th><br> <td>5</td><br> <td>April 5</td><br> </tr><br><br> <tr><br> <th <b>scope="row"</b>>Beth</th><br> <td>8</td><br> <td>January 14</td><br> </tr><br><br> </table><br> </code> <p>The <code>scope</code> attribute tells the browser and screen reader that everything within a column that is associated to the header with <code>scope="col"</code> in that column, and that a cell with <code>scope="row"</code> is a header for all cells in that row.</p> <p>All <code><th></code> elements should generally always have a scope attribute. While screen readers may correctly guess whether a header is a column header or a row header based on the table layout, assigning a scope makes this unambiguous.</p> <div class="section" id="complextables"> <h4>Spanned headers</h4> <p>Scope will apply even if the table is complex with multiple levels of headers (such as in spanned cells). The scope of a table header will apply to all cells over which that header spans.</p> <table> <caption>Shelly's Daughters</caption> <tr> <td></td> <th scope="col">Name</th> <th scope="col">Age</th> <th scope="col">Birthday</th> </tr> <tr> <th rowspan="2" scope="row">by birth</th> <th scope="row">Jackie</th> <td>5</td> <td>April 5</td> </tr> <tr> <th scope="row">Beth</th> <td>8</td> <td>January 14</td> </tr> <tr> <th scope="row">by marriage</th> <th scope="row">Beth</th> <td>8</td> <td>January 14</td> </tr> </table> <p>In this example, the "by birth" row header has a scope of row, as do the headers with the names. The cell showing the age for Jackie will have 3 headers - one column header ("Age") and two row headers ("by birth" and "Jackie"). A screen reader would identify all of them, including the data cell content (e.g., it might read "by birth. Jackie. Age. 5.").</p> <div class="note"> <div class="title">Note</div> <p>Despite being standard markup for tables for many years, some screen readers still do not fully support complex tables with spanned or multiple levels of row and/or column headers. When possible, try to 'flatten' the table and avoid spanned cells and multiple levels of header cells.</p> </div> </div> </div> <div class="section" id="id"> <h3>The <code>headers</code> and <code>id</code> attributes</h3> <p>Another way to associate data cells and headers is to use the <code>headers</code> and <code>id</code> attributes. This method is NOT generally recommended because <code>scope</code> is usually sufficient for most tables, even if the table is complex with multiple levels of headers.</p> <p>In extremely complex tables where <code>scope</code> may cause table headers to apply to (or have a scope for) cells that are not to be associated to that header, then <code>headers</code> and <code>id</code> may be used. In these cases, while <code>headers</code> and <code>id</code> might make the table technically accessible, if there are multiple levels of row and/or column headers being read, it will not likely be functionally accessible or understandable to a screen reader user.</p> <p>With this approach, each <code><th></code> is assigned a unique <code>id</code> attribute value. Then, each and every <code><td></code> cell within the table is given a <code>headers</code> attribute with values that match each <code><th> id</code> value the cell is associated to. The values are separated by spaces and should be listed in the order in which a screen reader should read them. If using headers/id in the example above, the cell for Jackie's age might be marked up as <code><td headers="birth jackie age">5</td></code>).</p> <p>Again, it should be emphasized that this method is more complex, uses much more markup (and potential to become broken), and is rarely necessary (use scope instead).</p> </div> </div> <div class="section" id="prop"> <h2>Use Proportional Sizing, Rather than Absolute Sizing</h2> <p>The rule that applies to layout tables also applies to data tables. Let the browser window determine the width of the table whenever possible, to reduce the horizontal scrolling required of those with low vision. If cell widths need to be defined, use relative values, such a percentages, rather than pixel values. Defined cell heights should generally be avoided so the cell can expand downward to accommodate its content - something especially useful for users with low vision that may enlarge text content.</p> </div> <div class="section" id="other"> <h2>Other table markup</h2> <div class="section"> <h3>Summary</h3> <p>The <code>summary</code> attribute of the <code><table></code> tag may be used to provide a summary of a data table structure (not content). Support for summary varies, but in general, it is screen reader specific (it's not accessible to anyone else) and is not well supported. Additionally, the <code>summary</code> attribute is not part of the HTML5 specification. In general, if a table is so complex that it needs an explanation of how it is structured, it probably is not very accessible and should probably be simplified. For these reasons, we do not recommend the use of summary. If it is used, it must never be used for layout tables.</p> </div> <div class="section"> <h3>thead, tfoot, and tbody</h3> <p>The <code>thead</code> and <code>tfoot</code> elements define header and footer rows for tables. They provide no accessibility functionality and are generally only of use when a long table is printed - the head and/or foot rows will repeat at the top or bottom of each printed page. Similarly, the <code>tbody</code> element defines the body content of a data table (meaning anything that's not a thead or tfoot). Again, this element does not provide any additional accessibility benefit, but there is no harm in using it for table styling or other reasons.</p> </div> </div> </article> <!-- --> <aside id="articlemeta"> <div id="updated">Last updated: <time datetime="2017-09-18">Sep 18, 2017</time></div> <div id="related"> <h2>Related Resources</h2> <ul> <li><a href="/articles/visual">Visual Disabilities</a></li> <li><a href="/techniques/screenreader/">Designing for Screen Reader Compatibility</a></li> </ul> </div> </aside> </main> <footer> <div id="footerresources"> <div class="footerblock"> <h2 id="copyright">©2025 WebAIM</h2> <p id="contact"> Utah State University<br> 6807 Old Main Hill<br> Logan, UT 84322-6807<br> <a class="phone" href="tel:4357977024">435.797.7024</a></p> <div id="checkpage"> <h2>Check Your Accessibility</h2> <form action="https://wave.webaim.org/report" novalidate> <label for="waveurl">Web site address:</label> <input type="url" id="waveurl" name="url" title="Web site address"> <input type="submit" value="WAVE"> </form> </div> </div> <div class="footerblock"> <h2 id="blog">From the Blog</h2> <ul><li><a href="/blog/join-the-discussion/">Join the Discussion鈥擣rom Your Inbox</a></li><li><a href="/blog/severity-ratings/">Using Severity Ratings to Prioritize Web Accessibility Remediation</a></li><li><a href="/blog/25-tips/">25 Accessibility Tips to Celebrate 25 Years</a></li><li><a href="/blog/celebrating-webaims-25th-anniversary/">Celebrating WebAIM's 25th Anniversary</a></li></ul> </div> <div class="footerblock"> <h2 id="popular">Popular Resources</h2> <ul> <li><a href="/training/virtual">WebAIM Training</a></li> <li><a href="/standards/wcag/checklist">WCAG 2 Checklist</a></li> <li><a href="/newsletter">WebAIM Monthly Newsletter</a></li> <li><a href="/resources/contrastchecker">Color Contrast Checker</a></li> <li><a href="/resources/designers/">Web Accessibility for Designers</a></li> <li><a href="http://wave.webaim.org/">WAVE Web Accessibility Evaluation Tool</a></li> </ul> </div> <div id="footerlinks"> <ul> <li><a id="footercontact" href="/contact">Contact</a></li> <li><a id="footerabout" href="/about">About</a></li> <li><a id="footerrss" href="/community/rss">RSS Feeds</a></li> <li><a id="footertwit" href="http://twitter.com/webaim">Twitter</a></li> <li><a id="footercopyright" href="/copyright">Copyright & Terms of Use</a></li> </ul> </div> <div class="clear"></div> </div> </footer> </body> </html>