Sunday, November 27, 2016

There are plenty of tutorials online for creating tabbed panels in HTML documents, some using JavaScript, some using pure CSS tricks. Most of the approaches seem to assume that a list of some type is the appropriate element to use for a tabbed interface, but I'd argue that lists are not semantically descriptive of tabbed interfaces. They either include the main tab content along with the tab name, like so:

It's simply bizarre to mix the tab name with the main tab content as with the first case. The tab name controls interaction with the tab content, it's not part of the tab's content. They are semantically distinct, and so should be distinct in the markup.

In the second case, name and content are separated, but not in a semantically meaningful way, which makes it invisible to screen readers unless you add extra annotations. The connection between tab name and tab content is completely indirect since it depends upon interpreting the meaning of a link's target as referring to an element in the current document. This is obviously only one approach to separating tab name from content, but every approach I've seen so far makes a similar tradeoff: no technique expresses the relationship between tab name and tab content using markup that properly describes their relationship in a semantically meaningful way.

So what is the semantic relationship between tab name and tab content? Well clearly the tab name is a heading of some kind that summarizes and/or meaningfully describes the content it references.

Secondly, a set of tabs are logically related in some larger context, and so markup that also expresses a grouping is the most semantically meaningful. For instance, expressing tab content as a set of divs doesn't express this association, nor does expressing tab names as standard headings H1..H6.

However, there is an HTML element that provides headings and semantically associates those headings with its contents: tables!

The table headings are the tab names, and the table cells contain its contents. Each cell designates the header/tab name to which it belongs, which is meaningful semantic markup for tabbed interfaces. Now all that remains is providing the interactive nature of tabbed interfaces. I think most of the standard techniques will work just as well here, but I used a simple javascript function and some basic CSS you can see in this jsfiddle. Basically, the CSS sets the backgrounds, borders and mouseover behaviour needed to mimic the familiar tab layout:

Basically, the headers are all floated left and the the active tab content is tracked as a property of the table. The headings capture the click event and modify the display styling property of the tab content and the active tab name/heading.

I'm no CSS or javascript wizard, so this can all probably be improved, but it suffices to make the point that mimicking tabbed interfaces using tables is a good semantic fit.

Given the use of DomElement.classList, I believe this requires IE10 or up, but it certainly could be ported to older browsers without too much difficulty.

Edit: here's a better semantic version using the <nav> tag for the tabs, since tabs are semantically a type of navigation within the current document. Each nav link directly references the id of the corresponding tabbed content. All you need to do is decorate the outer block with "tabbed" to get the dynamic tab interface.