25

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?

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • Is the hierarchy of your actual information limited to two levels (as it is in your example)? – Zero Piraeus Jul 20 '13 at 01:50
  • @ZeroPiraeus No, it is of an arbitrary depth, but probably no more than 5-8 in practice. –  Jul 20 '13 at 01:54
  • 1
    I dont't know, what's wrong with a table. I think, this __IS__ tabular data, because it comes in rows and cols. This does not change by the hierarchy – yunzen Jul 26 '13 at 11:02

7 Answers7

24

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:

  1. Represent the information with nested lists of some sort, and rely on CSS to make the result look like a table.

  2. 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:

  1. The header/detail relationship between e.g. 'Item Name' and 'Identifier' etc.

  2. 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.

Zero Piraeus
  • 56,143
  • 27
  • 150
  • 160
  • Careful, id attributes cannot start with a numerical digit. – Matt Sach Jul 26 '13 at 12:02
  • 8
    @MattSach That's [no longer true](http://www.w3.org/TR/html-markup/global-attributes.html#common.attrs.id) in HTML5. – Zero Piraeus Jul 26 '13 at 12:05
  • 1
    Well blow me down with a feather, I had no idea that had changed. Thanks! – Matt Sach Jul 26 '13 at 12:37
  • Nice answer. As for the `table` solution, wouldn't it be better to use the [headers attribute](http://www.w3.org/TR/2014/NOTE-WCAG20-TECHS-20140311/H43) instead of making up your own (`data-parent`)? The `headers` attribute is also read by screen readers, but AFAIK it can only be applied to individual cells (e.g. the `seq` or `item name` cells) and not entire rows. – JohnCand Apr 24 '14 at 09:43
8

I would present it by using a table and by adding custom data attributes to the td tags:

<table id="myTable" class="table">
    <tr>
        <td data-indent="0">1</td>
        <td data-indent="0">Test</td>
        <td data-indent="0">Test 1</td>
    </tr>
    <tr>
        <td data-indent="1">1.1</td>
        <td data-indent="1">Another</td>
        <td data-indent="0">Test 1.1</td>
    </tr>
    <tr>
        <td data-indent="2">1.1.1</td>
        <td data-indent="3">Another</td>
        <td data-indent="0">Test 1.1.1</td>
    </tr>
        <tr>
        <td data-indent="2">1.1.2</td>
        <td data-indent="3">Another one</td>
        <td data-indent="0">Another test 1.1.2</td>
    </tr>
    <tr>
        <td data-indent="0">2</td>
        <td data-indent="0">Test</td>
        <td data-indent="0">Test 2</td>
    </tr>
</table>

Then, with the help of jQuery, set the padding of each cell value in your table:

$("td")
    .css("padding-left", function (index) {
    return 10 * parseInt($(this).data("indent")) + "px";
});

See it working on jsFiddle.

Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • 2
    Why not do the padding through css? You can match the cells to pad trough td:first-child[data-indent="1"] or td:first-child[data-indent="2"] and apply the needed padding. – Lars Ebert Jul 17 '13 at 06:45
  • 2
    For what I can see though, the problem with this is you lose the semantics of the hierarchy. –  Jul 17 '13 at 10:52
3

I think there are two sensible ways how to represent this in HTML:

  • use a table and make the relation/hierarchy explicit with natural language
  • use sectioning elements (resp. headings if you use HTML 4.01)

table with a column explaining the hierarchy

If there is no markup for defining this relationship, you should use text. If the visual representation is unambiguous, you could visually hide this text so that it is only accessible for screenreader/text browser users.

In your case, you could add a column that explains the relationship of rows that are "sub items":

<table>

  <tr>
    <th>Seq</th> 
    <th>Relation</th> <!-- or some clever better label -->
    <th>Item Name</th>
    <th>Min</th>
    <th>Max</th>
  </tr>

  <!-- … -->

  <tr id="2">
    <td>2</td>
    <td></td> <!-- "parent", "root", "container", empty -- whatever makes sense for your case -->
    <td>Name</td>
    <td>1</td>
    <td>1</td>
  </tr>

  <tr id="2.1">
    <td>2.1</td>
    <td>child of <a href="#2">Name</a></td>
    <td>First Name</td>
    <td>1</td>
    <td>1</td>
  </tr>

</table>

Each row could get an id (with value of Seq or Item Name), so that this row can be linked {note that id values starting with a digit are not allowed in HTML 4.01; you could use something like id="seq-2.1" there}. If an item is a child of another item, you could link to the row of the parent item.

This way you make it clear for humans, and machines still see that these rows are connected, although the specific semantics of this relation is not machine-readable. You could use a link type (rel value) here if to make the meaning of the relation explicitly clear. In HTML 4.01 you could create a value yourself, in HTML5 it would need to be registered first.

sectioning elements / headings

Instead of using a table, you could make use of HTML’s outlining. {The following example uses HTML5’s sectioning elements. If you use HTML 4.01, simply replace the sectioning elements with div (or no element at all) and use headings only.}

Each section (introduced by a heading) represents an item. The outline of the headings (resp. nesting of the sectioning elements) represents the hierarchy of your items.

Here is an example to see the whole structure:

 <article>

   <h1><!-- heading for the whole data --></h1>

   <section class="item" id="1">
     <h2>Identifier</h2>
   </section>

   <section class="item" id="2">
     <h2>Name</h2>

     <section class="item" id="2.1">
       <h3>First Name</h3>
     </section>

     <section class="item" id="2.2">
       <h3>Middle Name</h3>
     </section>

     <section class="item" id="2.3">
       <h3>Last Name</h3>
     </section>

   </section>

   <section class="item" id="3">
     <h2>Age</h2>
   </section>

 </article>

Each section could contain a dl for the properties:

<section class="item" id="3">
  <h2>Age</h2>

  <dl>
    <dt>Min</dt>
    <dd>1</dd>
    <dt>Max</dt>
    <dd>1</dd>
  </dl>

</section>

Depending of the actual meaning of your content, you could use the code element for the item names (e.g. if it describes elements of a markup language, for example), and/or the dfn element, if the following content is a definition of that item.

unor
  • 92,415
  • 26
  • 211
  • 360
2

I think you should use a table. True, the hierarchy is more important, but it also can be displayed through manually writing down the first column. But the attributes min, max and item name could not be shown as easily in a list as in a table. My opinion: use a table and provide the seq column manually!

Lars Ebert
  • 3,487
  • 2
  • 24
  • 46
2

My suggestion would be to use nested ordered lists to retain your hierarchical structure, and then description lists to represent the "columns" for each row.

For example, the description list for the first row could look something like this:

<dl>
  <dt>Item Name</dt>
  <dd>Identifier</dd>
  <dt>Min</dt>
  <dd>1</dd>
  <dt>Max</dt>
  <dd>1</dd>
  <dt>Notes</dt>
  <dd>(Required)</dd>
</dl>

You would have to use CSS to hide the description terms (since you don't want them showing up on every row) and to adjust the layout to look more like a table.

The downside to this format is that you are going to be duplicating the column headings on every single row. But semantically I think that makes the most sense, and it should also make the content more meaningful to a screen reader.

I've made a first attempt at the CSS for this so you can get an idea of how it could work. This is probably not very well done, but at least it'll give you something to start with.

CodePen Link

James Holderness
  • 22,721
  • 2
  • 40
  • 52
2

UPDATE: I've added the use of IDs and "headers" attribute to, somehow, semantically mark up the hierarchy.

That's definitively tabular data (you should really push the definition of "list" to justify using an UL or DL here!).

I think a good approach would be using different tbodys to group those related rows together (something like this it used here http://www.w3.org/TR/2012/WD-html5-20120329/the-table-element.html#the-table-element see "table being used to mark up a Sudoku puzzle")

<table>
  <thead>
    <tr>
      <th id="seq">Seq</th>
      <th>Item Name</th>
      <th>Min</th>
      <th>Max</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th id="s1" headers="seq">1</th>
      <td>Identifier</td>
      <td>1</td>
      <td>1</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th id="s2" headers="seq">2</th>
      <td>Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub">
      <th id="s2_1" headers="seq s2">2.1</th>
      <td>First Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub">
      <th id="s2_2" headers="seq s2">2.2</th>
      <td>Middle Name</td>
      <td>-</td>
      <td>-</td>
    </tr>
    <tr class="sub">
      <th id="s2_3" headers="seq s2">2.3</th>
      <td>Last Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub sub">
      <th id="s2_3_1" headers="seq s2 s2_3">2.3.1</th>
      <td>Last Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
    <tr class="sub sub">
      <th id="s2_3_2" headers="seq s2 s2_3">2.3.2</th>
      <td>Last Name</td>
      <td>1</td>
      <td>1</td>
    </tr>
  </tbody>
  <tbody>
    <tr>
      <th id="s3" headers="seq">3</th>
      <td>Age</td>
      <td>-</td>
      <td>1</td>
    </tr>
  </tbody>
</table>

Then you could use something like this:

table { border-collapse: collapse; }
tbody { border-bottom:1px solid #000; }
tbody .sub td { padding-left: 10px; }

If fact, I think you can only use tbody to group rows together and leave single rows alone

<tr>
  <td>1</td>
  <td>Identifier</td>
  <td>1</td>
  <td>1</td>
</tr>
<tbody>
  <tr>
    <td>2</td>
    <td>Name</td>
    <td>1</td>
    <td>1</td>
  </tr>
  <tr class="sub">
    <td>2.1</td>
    <td>First Name</td>
    <td>1</td>
    <td>1</td>
  </tr>
  ...
</tbody>
<tr>
  <td>3</td>
  <td>Age</td>
  <td>-</td>
  <td>1</td>
</tr>
Coluccini
  • 688
  • 1
  • 7
  • 18
  • Using `tbody` to group elements won't work when there are multiple levels of hierarchy, as OP has stated in the comments. – Zero Piraeus Jul 26 '13 at 12:13
  • 1
    There's a "headers" attribute you can use to somehow mark the hierarchy. I'll make a example and edit the post in a minute. – Coluccini Jul 26 '13 at 15:43
  • Interesting; I wasn't aware of `headers`, and that's a good use case. But how are you going to use it as a CSS hook to visually represent the depth of the hierarchy, past the two levels your use of `tbody` gives you? – Zero Piraeus Jul 26 '13 at 19:39
  • For visually representation you could use different class names at each level (I've used an option on the example, but you could also use something like "level_0", "level_1", "level_2", etc too). – Coluccini Jul 27 '13 at 20:45
0

Why not both? A tree grid is a good way to represent tabular data that also conforms to a hierarchy.

This is one such example.

However, having used Extjs on two very large projects, my own personal recommendation is to stay away from it if you're going to be producing a large application. While it may be fine for a one-off grid, I personally find that it's poorly implemented and can become more cumbersome as the size of the project increases. However, it is very feature rich, so the examples panel may give you some more ideas on grids (tables) that might help you.

Keep in mind that you should always be asking yourself, "what questions are my users trying to answer?" Then, ask yourself, "which graphical devices give the clearest and simplest path to answering that question?"

One book that really helped me with these questions was the dashboard design book. Even though you may not be building a dashboard, it has many UX techniques and theories that have made it easier for me when selecting the appropriate UI element (with respect to data).

Hope that helps...

Homer6
  • 15,034
  • 11
  • 61
  • 81
  • I'm not sure I'd describe `
    ` (from your linked example) as a semantic representation of the data ... it *is* a very Extjs approach though ;-)
    – Zero Piraeus Jul 20 '13 at 03:49
  • I'm not sure it's good form to criticize others' answers when you've posted one of your own. He asked about representing data in a web user interface. Does that mean "HTML only"? Because I certainly wouldn't consider that the current state of the web. Javascript is an invaluable user interface tool. – Homer6 Jul 20 '13 at 03:55
  • 4
    No offence was intended ... in my experience it *is* common to point out potential shortcomings of an answer in the comments, regardless of whether the commenter has also given an answer (it's certainly happened to me). On your second point: Javascript or no javascript, I think it's legitimate to criticise "not representing the data at all" as a way of representing the data. OP clearly cares about semantic markup, and the example you link to is anything but. – Zero Piraeus Jul 20 '13 at 04:10
  • ... if it helps, I just upvoted one of your answers elsewhere :-) – Zero Piraeus Jul 20 '13 at 04:13
  • 3
    @Homer6 Part of the challenge, is I am seeking a "HTML only" solution. Screen readers and other accessibility-browsers can restrict the use of CSS and JS, so a HTML only solution is preferred. –  Jul 21 '13 at 23:28