Interactive elements within a grid layout
Often times, the best way to begin marking up HTML content is to put aside the visual design and concentrate on the semantics. A good example of this is when a design first appears to be a data table but actually includes content other than data.
The Challenge
In the following wireframe design, transaction records are displayed in a table-like format, a grid. Each row is designed to be a link (the entire row) and has a grey hover/focus effect. Data includes a date, description, and dollar amount. There is also a menu button in each of the records; clicking it opens a drop down menu.
At first glance, the design appears to be a data table. But the row link and the menu button within a data table create fundamental markup and accessibility issues. (If the design called for traditional text links instead of the row link and menu button, a data table is a solid option.) A layout table would create similar issues as a data table but we’re not going to go there in the name of Web Standards.
First Approaches
Definition List
One idea for marking up this content is to use a description list. For each row, a unique identifier (like a record number) would be the DT and would be visually hidden. The rest of the row content would be contained in DD elements. Example:
<dl>
<dt>Record 1</dt>
<dd>date</dd>
<dd>description</dd>
<dd>amount</dd>
<dd>[menu button]</dd>
</dl>
But like the table, the row link would certainly be challenging, and would add to the complexity of the extensive CSS already required to make this fit the visual design. Also, the menu button doesn’t fit the semantic meaning of a DD (description data).
ARIA Grid
Another approach is to use divs and spans with the ARIA grid role along with the associated row and gridcell roles. In this technique, “the grid construct describes relationships between data such that it may be used for different presentations”. In other words, a more flexible data table-like structure can be developed. Example:
<div role="grid">
<div role="row">
<a href="#">
<span role="gridcell" class="date">date</span>
<span role="gridcell" class="desc">description</span>
<span role="gridcell" class="price">amount</span>
</a>
<span role="gridcell" class="menu">[menu button]</span>
</div>
</div>
To give context to screen reader users, it may be a good idea to add the aria-labelledby property and the rowheader and columnheader roles.
The main problem with this technique is support. ARIA is still relatively new, and inconsistent results are found among the different screen readers (JAWS, NVDA, VoiceOver). There is also a lack of semantic elements, and the abundance of ARIA creates code complexity (especially to those not yet familiar with ARIA).
A Solution
Let’s take a step back and simplify. There are three main piece to the puzzle: a unique identifier (not in visual design), some linked text, and a menu button.
One feasible solution is to use:
- a heading as the unique identifier for each record (like the DT in the example above),
- an anchor element containing spans for the link (like the ARIA example above),
- a div to contain the menu button.
Divs are also used for CSS hooks in order to create the grid/table-like design. Example:
<div class="table">
<div class="tableRow">
<h3>Record 1</h3>
<div class="tableRowInner">
<a href="foo.html">
<span class="tableColumn date">date</span>
<span class="tableColumn desc">description</span>
<span class="tableColumn price">amount</span>
</a>
</div>
<div>[menu button]</div>
</div>
</div>
For the title of the grid content, let’s use a heading, say an H2 in this case. For proper heading levels, each record will then require an H3 heading. This is great for not only page structure but also helps screen readers users for context and navigation. The menu button is separated in its own Div but still falls under the record’s H3 heading.
Using CSS we create the grid design. Here’s an excerpt:
.tableRow .tableColumn {
display: block;
float: left;
color: #333;
}
.tableRow .tableRowInner > a {
display: block;
float: left;
padding: .75rem 0;
text-decoration: none;
width: 118%;
}
.tableRowInner {
float: left;
width: 85%;
}
.tableRow:last-child .tableRowInner {
padding-bottom: 1.5em;
}
.tableRow .tableColumn.date {
width: 25%;
}
.tableRow .tableColumn.desc {
width: 40%;
}
.tableRow .tableColumn.price {
text-align: right;
width: 25%;
}
With some CSS magic, we can position the menu button to appear within the row (check the widths of the row and anchor). And there we have it; a grid layout with interactive elements which is accessible. It also a robust solution; it functions well without JavaScript or without CSS.
Final Words
Developing ideal solutions can be difficult in these days of complex web apps, stringent design requirements, and increasing accessibility concerns. The solution in this article isn’t perfect (could use less divs and spans and more semantic elements), but it certainly does the job. Do you have any suggestions for this issue?