skip to Main Content

According the HTML5 spec, th elements are not allowed to have heading elements inside of them. However, this provides a weird order in the heading map depending on the content surrounding the table.

In this case, the table topic 2 may have certain content (in the second td) which can have a subheading. To follow the heading structure previously layed out, you would expect to have to use a h3 here. But if you would later use a screenreader tool, you would miss the fact that this h3 is a subheading of table topic 2.

<h2>Lorum Ipsum</h2>
<p>Dolor sit amet, consectetur adipiscing elit.</p>

<table>
   <thead>
      <tr>
         <th>Table topic 1</th>
         <th>Table topic 2</th>
         <th>Table topic 3</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <td>Lorum ipsum...</td>
         <td>
            Dolor sit amet...
            <h3>Table topic 2 Subheading</h3>
            Consectetur adipiscing elit...
         </td>
         <td>Donec malesuada congue...</td>
      </tr>
   </tbody>
</table>

What would be the correct solution here? Use H3? Or use H4 instead, to at least signify that there is something in between, even though that "something" doesn’t appear in the heading structure.

2

Answers


  1. Don’t skip a heading level. Heading elements (<h2>, <h3>, etc) help define the document outline. Table heading elements <th> don’t contribute to the document outline.

    While it’s valid HTML to include heading elements within table cells, it’s worth considering if there’s a more appropriate alternative way to mark up that content so that the document outline doesn’t bleed into the contents of a table. Without seeing your real content, it’s hard to know what approach to take, but some options to consider would be:

    • A more complex table that uses multiple sets of table headings to convey substructure
    • Nested tables
    • Not using tables at all and instead using other semantic elements to show relationships between types of content
    Login or Signup to reply.
  2. I’ll second what Sean said about not skipping levels, although the oft-promised "document outline" thing has never seen a finished implementation in any browser, so it is more of a conceptual guideline than a formal spec.

    In theory, certain semantic elements (such as <section>) are allowed to "reset" the heading levels, so you could place one of those inside the <td>, to wrap any of the "document-like" content inside the cell in a meaningful semantic unit starting again with <h1>. I am not sure exactly how assistive tech will handle this, and any "deep nesting" represents an additional cognitive load, but it conforms with the spec, so it might be worth testing.

    For a really lightweight approach, you could also consider using role="group" with aria-labelledby. Something like this:

    <td>
        Dolor sit amet...
        <p id="foo" aria-hidden="true">Table topic 2 Subheading</p>
        <div role="group" aria-labelledby="foo">
           <!--the content that deserves the subheading goes here-->
        </div>
    </td>
    

    Not quite as emphatic as a heading, but since group names don’t have/need levels, it will not upset your immaculate heading level structure.

    The aria-hidden on the <p> is intended to stop duplicate announcements. (The pseudo-heading will be announced when the screen reader "cursor" hits the div).

    You can put the pseudo-heading inside the group if you prefer, and it should still work fine.

    Note that aria-label and aria-labelledby are ignored for certain semantics, so you’ll need a role (or element type) that actually permits naming in the ARIA or HTML-AAM spec if you want to use this approach. Without knowing more about your use case, role="group" seems like a good choice here, but depending on the actual content, there may be something better.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search