I'm working to redesign a legacy toolset and I'm looking at how to better display some information both presentationally and semantically.
The data hierarchically in nature but has properties that need to be readily visible to users. The desired layout is similar to below.
Seq Item Name Min Max - Anything under here isn't shown
1 Identifier 1 1 (Required)
2 Name 1 1
2.1 First Name 1 1
2.2 Middle Name - - (Optional but unlimted)
2.3 Last Name 1 1
3 Age - 1 (Optional)
At the moment this is one entire table, and the intdenting for the Sequence (Seq
) number is achieved by inserting additional table cells to kind of bump everything across to the right.
The challenge I have is figuring out how to effectively display this information.
First of all is this tabular data? I would say no, as the hierarchy is important, and the 'columns' are merely attributes of the item in each 'row'.
If it isn't tabular, what is it and how would that be done ? I would personally argue this is a set of nested UL
lists - the sequence number is optional and not always a number. If its a set of lists, that will indent sublists correctly, but what is the best way of presenting the short attributes?
If it is a table, what is the best way to present the semantic existance of the hierarchy in the table?
The challenge here is that the information you want to represent is in one respect tabular (it's a set of items which have identically-labelled attributes), and in another hierarchical (items have parents).
Unfortunately, there's no nested grouping mechanism for table rows in HTML: tbody
can be used to group rows, but nesting it is illegal (except with an intermediate table
inside a td
, which is pretty horrible).
That leaves you with two choices:
Represent the information with nested lists of some sort, and rely on CSS to make the result look like a table.
Represent the information as a table, and rely on attributes of some sort to represent its hierarchical relationships.
Here are some examples of how you could implement those choices:
Using nested lists (naïve approach):
<ul>
<li>
<dl>
<dt>Seq</dt> <dd>1</dd>
<dt>Item Name</dt> <dd>Identifier</dd>
<dt>Min</dt> <dd>1</dd>
<dt>Max</dt> <dd>1</dd>
</dl>
</li>
<li>
<dl>
<dt>Seq</dt> <dd>2</dd>
<dt>Item Name</dt> <dd>Name</dd>
<dt>Min</dt> <dd>1</dd>
<dt>Max</dt> <dd>1</dd>
</dl>
<ul>
<li>
<dl>
<dt>Seq</dt> <dd>2.1</dd>
<dt>Item Name</dt> <dd>First Name</dd>
<dt>Min</dt> <dd>1</dd>
<dt>Max</dt> <dd>1</dd>
</dl>
</li>
<li>
<dl>
<dt>Seq</dt> <dd>2.2</dd>
<dt>Item Name</dt> <dd>Middle Name</dd>
<dt>Min</dt> <dd>-</dd>
<dt>Max</dt> <dd>-</dd>
</dl>
</li>
<li>
<dl>
<dt>Seq</dt> <dd>2.3</dd>
<dt>Item Name</dt> <dd>Last Name</dd>
<dt>Min</dt> <dd>1</dd>
<dt>Max</dt> <dd>1</dd>
</dl>
</li>
</ul>
</li>
<li>
<dl>
<dt>Seq</dt> <dd>3</dd>
<dt>Item Name</dt> <dd>Age</dd>
<dt>Min</dt> <dd>-</dd>
<dt>Max</dt> <dd>1</dd>
</dl>
</li>
<ul>
This handles the hierarchical aspect of the information, but you end up repeating yourself a lot, and are going to have to jump through some hoops in the CSS to display the result in a tabular way. It's likely doable with judicious use of :first-child
, but the end result is that you've gone out of your way to mark something up that you want to present as a table in a non-tabular way, and as a result given yourself more work pulling it back into shape.
It also makes the genuinely tabular nature of the relationships between the items implicit rather than explicit in the markup - without referring to the rendered output, it isn't clear that these items will always have the same number and kind of attributes.
Using nested lists ("clever" approach):
<dl>
<dt>
<ul> <li>Seq</li> <li>Item Name</li> <li>Min</li> <li>Max</li> </ul>
</dt>
<dd>
<ul> <li>1</li> <li>Identifier</li> <li>1</li> <li>1</li> </ul>
</dd>
<dd>
<dl>
<dt>
<ul> <li>2</li> <li>Name</li> <li>1</li> <li>1</li> </ul>
</dt>
<dd>
<ul> <li>2.1</li> <li>First Name</li> <li>1</li> <li>1</li> </ul>
</dd>
<dd>
<ul> <li>2.2</li> <li>Middle Name</li> <li>-</li> <li>-</li> </ul>
</dd>
<dd>
<ul> <li>2.3</li> <li>Last Name</li> <li>1</li> <li>1</li> </ul>
</dd>
</dl>
</dd>
<dd>
<ul> <li>3</li> <li>Age</li> <li>-</li> <li>1</li> </ul>
</dd>
</dl>
Here, we're using description lists to describe two things:
The header/detail relationship between e.g. 'Item Name' and 'Identifier' etc.
The parent/child relationship between e.g. the 'Name' unit and the 'First Name' unit.
It's certainly more compact, but unfortunately the specific relationship between each header and its detail elements is implicit at best, and without additional styling to visually organize the information in a tabular way, it'll be even less obvious when rendered what's actually being represented.
Using a table
:
<table>
<thead>
<tr>
<th>Seq</th> <th>Item Name</th> <th>Min</th> <th>Max</th>
</tr>
</thead>
<tbody>
<tr id=100>
<td>1</th> <th>Identifier</th> <td>1</td> <td>1</td>
</tr>
<tr id=200>
<th>2</th> <th>Name</th> <td>1</td> <td>1</td>
</tr>
<tr id=210 data-parent=200 class=level-1>
<th>2.1</th> <th>First Name</th> <td>1</td> <td>1</td>
</tr>
<tr id=220 data-parent=200 class=level-1>
<th>2.2</th> <th>Middle Name</th> <td>-</td> <td>-</td>
</tr>
<tr id=230 data-parent=200 class=level-1>
<th>2.3</th> <th>Last Name</th> <td>1</td> <td>1</td>
</tr>
<tr id=300>
<th>3</th> <th>Age</th> <td>-</td> <td>1</td>
</tr>
</tbody>
</table>
Here, the parent/child relationships are explicitly described by the data-parent
attribute (which can be accessed via javascript if necessary), and a class=level-{n}
attribute provides a hook that can be used by the CSS:
.level-1 > th {
padding-left: 1em;
}
Ultimately it's a matter of personal preference and convenience, but I think the <table>
approach is better simply because it satisfies the "does it look reasonable with no CSS?" rule of thumb much better than either of the nested-lists approaches above.