How to use “keys” and “description” cell in a table row – Table Usability

This article are part of “What’s an usable table ?“, table usability guideline. The purpose of the table usability guideline is to explain how you can create usable complex table. The HTML 5 markup are used to illustrate the guideline methodology. Currently in progress, I am working on a javascript html table parser that would support the usable table guideline. Anything regards of HTML accessibility are not discussed here because one of my goal is to auto setup all the accessibility on the fly for a complex usable table.

Key Cell

Defined by a data cell element (td), a key cell can by compared to a primary key in a table inside a relational database. A key cell are always associated to a row cell header (th). Only one key cell can be associated to a header but two key cell can co-exist in the same table row. A key cell is always at the left of his cell header.

Basic “Key Cell” Example
Product ID Product Name Col 1 Col 2 Col 3 Col 4
66-A Famous ++++ ++++ ++++ ++++
94-C Interresting ++++ ++++ ++++ ++++
27-F Misterious ++++ ++++ ++++ ++++
68-H Questionable ++++ ++++ ++++ ++++
30-S Hottest ++++ ++++ ++++ ++++
04-W Passable ++++ ++++ ++++ ++++

 

 

Source code
 

<table class="lined">
	<caption>Basic &quot;Key Cell&quot; Example</caption>
    
    <thead>
    	<tr>
        	<th>Product ID</th>
            <th>Product Name</th>
            <th>Col 1</th>
            <th>Col 2</th>
            <th>Col 3</th>
            <th>Col 4</th>
    	</tr>
    </thead>
    <tbody>
    	<tr>
        	<td>66-A</td>
            <th>Famous</th>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
        </tr>
    	<tr>
        	<td>94-C</td>
            <th>Interresting</th>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
        </tr>
    	<tr>
        	<td>27-F</td>
            <th>Misterious</th>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
        </tr>
    	<tr>
        	<td>68-H</td>
            <th>Questionable</th>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
        </tr>
    	<tr>
        	<td>30-S</td>
            <th>Hottest</th>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
        </tr>
    	<tr>
        	<td>04-W</td>
            <th>Passable</th>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
            <td>++++</td>
        </tr>

	</tbody>
</table>

 

 

As you can see in the previous table, the first table column are used to associate a product ID information to the product name. Whatever, it would not be clear to everybody, that doesn’t know/search for a specific product, to use the product ID. It’s most usable to use the product name. Keep in mind, when a entreprise market a product, he would use the product name and not the product key. The product key would be most useful for somebody that already know about it.

Another “Key Cell” Example – Android (Operating system) Release date
ID Version Release date
4.0.x Ice Cream Sandwich October 19, 2011
3.x.x Honeycomb February 22, 2011
2.3.x Gingerbread December 6, 2010
2.2 Froyo May 20, 2010
2.0, 2.1 Eclair October 26, 2009
1.6 Donut September 15, 2009
1.5 Cupcake April 30, 2009

 

 

Source Code
 

<table class="lined">
	<caption>Another &quot;Key Cell&quot; Example - Android (Operating system) Release date</caption>
    
    <thead>
    	<tr>
        	<th>ID</th>
            <th>Version</th>
            <th>Release date</th>
    	</tr>
    </thead>
    <tbody>
    	<tr>
        	<td>4.0.x</td>
            <th>Ice Cream Sandwich</th>
            <td>October 19, 2011</td>
        </tr>
    	<tr>
        	<td>3.x.x</td>
            <th>Honeycomb</th>
            <td>February 22, 2011</td>
        </tr>
    	<tr>
        	<td>2.3.x</td>
            <th>Gingerbread</th>
            <td>December 6, 2010</td>
        </tr>
    	<tr>
        	<td>2.2</td>
            <th>Froyo</th>
            <td>May 20, 2010</td>
        </tr>
    	<tr>
        	<td>2.0, 2.1</td>
            <th>Eclair</th>
            <td>October 26, 2009</td>
        </tr>
    	<tr>
        	<td>1.6</td>
            <th>Donut</th>
            <td>September 15, 2009</td>
        </tr>
    	<tr>
        	<td>1.5</td>
            <th>Cupcake</th>
            <td>April 30, 2009</td>
        </tr>

	</tbody>
</table>


 

 

If you check the similar table in wikipedia on the Adroid webpage, you will see the same relationship but displayed in an implicit way. They use emphasis in the first column to distinguish the key cell versus the row title.

 

Complex Key Cell Structure

Imagine you have serveral products and you want them to be classified by sector. You have an ID for each sector and an ID for each product. You would have a table like this:

SectorProduct NameCustomer PriceDistributor Price

Product Listing
ABC Exterior 2C57-ABC BBQ 135 $ 83 $
3C57-ABC Mowers 256 $ 199 $
A584-ABC Tractors 2145 $ 1687 $
XYZ Interior 2C57-XYZ Table 257 $ 205 $
3C57-XYZ Chair 49 $ 20 $
A584-XYZ Recycling Center 91 $ 56 $

 

 

Source Code
 


<table class="lined">
	<caption>Product Listing</caption>
    
    <thead>
    	<th colspan="2">Sector</th>
        <th colspan="2">Product Name</th>
        <th>Customer Price</th>
        <th>Distributor Price</th>
    </thead>

    <tbody>
    	<tr>
        	<td rowspan="3">ABC</td>
            <th rowspan="3">Exterior</th>
            
            <td>2C57-ABC</td>
            <th>BBQ</th>
            <td>135 $</td>
            <td>83 $</td>
        </tr>
        
        <tr>
            <td>3C57-ABC</td>
            <th>Mowers</th>
            <td>256 $</td>
            <td>199 $</td>
        </tr>

        <tr>
            <td>A584-ABC</td>
            <th>Tractors</th>
            <td>2145 $</td>
            <td>1687 $</td>
        </tr>


    	<tr>
        	<td rowspan="3">XYZ</td>
            <th rowspan="3">Interior</th>
            
            <td>2C57-XYZ</td>
            <th>Table</th>
            <td>257 $</td>
            <td>205 $</td>
        </tr>
        
        <tr>
            <td>3C57-XYZ</td>
            <th>Chair</th>
            <td>49 $</td>
            <td>20 $</td>
        </tr>

        <tr>
            <td>A584-XYZ</td>
            <th>Recycling Center</th>
            <td>91 $</td>
            <td>56 $</td>
        </tr>
	</tbody>
</table>
 

 

 

Description Cell

There exist other technique on how to add descriptive cell to a cell header. One of those technique is to add in superscript a footnote. An other technique is to use the “details/summary” HTML 5 element in a cell header. Those two technique can be applied to any data cell in a table. When we look at the cell header (th), a thrid technique can be used. That technique is to add a data cell directly in the next column of (right of) the cell heading. A cell header can only have one descriptive data cell associated to.

“Description Cell” example
Group Description Item Col 1 Col 2 Col 3
Heading 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem magna, mollis ac tempor id, bibendum ut turpis. Pellentesque odio ligula, egestas eu viverra ut, sodales vel sem. Nunc eu. Sub Heading 1a Data Data Data
Sub Heading 1b Data Data Data
Sub Heading 1c Data Data Data
Sub Heading 1d Data Data Data
Sub Heading 1e Data Data Data
Sub Heading 1f Data Data Data
Heading 2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem magna, mollis ac tempor id, bibendum ut turpis. Pellentesque odio ligula, egestas eu viverra ut, sodales vel sem. Nunc eu. Sub Heading 2a Data Data Data
Sub Heading 2b Data Data Data
Sub Heading 2c Data Data Data
Sub Heading 2d Data Data Data
Sub Heading 2e Data Data Data
Sub Heading 2f Data Data Data

 

 

Source Code



<table class="lined">
	<caption>&quot;Description Cell&quot; example</caption>
    
    <thead>
    	<tr>
            <th>Group</th>
            <th>Description</th>
            <th>Item</th>
            <th>Col 1</th>
            <th>Col 2</th>
		    <th>Col 3</th>
    	</tr>
    </thead>
    
    <tbody>
    	<tr>
        	<th rowspan="6">Heading&nbsp;1</th>
            <td rowspan="6">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem magna, mollis ac tempor id, bibendum ut turpis. Pellentesque odio ligula, egestas eu viverra ut, sodales vel sem. Nunc eu. </td>
            <th>Sub&nbsp;Heading&nbsp;1a</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;1b</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;1c</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;1d</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;1e</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;1f</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>


   	<tr>
        	<th rowspan="6">Heading&nbsp;2</th>
            <td rowspan="6">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse lorem magna, mollis ac tempor id, bibendum ut turpis. Pellentesque odio ligula, egestas eu viverra ut, sodales vel sem. Nunc eu. </td>
            <th>Sub&nbsp;Heading&nbsp;2a</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;2b</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;2c</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;2d</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;2e</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Sub&nbsp;Heading&nbsp;2f</th>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
    </tbody>
</table>

 

 

The previous description cell are explicited defined when it is located between two cell header. Sometime they exist descrive cell but without any hiarchical cell. It is in that case the column grouping (colgroup element) are useful.

Column Group Header

Rarely used, the column grouping can became very useful if we need to have a distinction between the data column group and the header column group. Here I apply the same rule as defined for the table row grouping (thead, tfoot, tbody). In the HTML specification it’s said that, if present, the thead row group are defined before any tfoot and tbody. So if we check the row group structure the row group header section are always the first. Now let apply the same approch to the colgroup structure. We have, the first colgroup element are used as an header group. Offcourse, if in the table body there are no row heading, that means there would not have a colgroup used as an header group.

Descriptive cell defined with colgroup

<colgroup span="2" /><colgroup span="3" />
“Description Cell” example – with one header per row
Item Description Col 1 Col 2 Col 3
Heading 1 Lorem ipsum dolor sit amet. Data Data Data
Heading 2 Lorem ipsum dolor sit amet. Data Data Data
Heading 3 Lorem ipsum dolor sit amet. Data Data Data
Heading 4 Lorem ipsum dolor sit amet. Data Data Data
Heading 5 Lorem ipsum dolor sit amet. Data Data Data
Heading 6 Lorem ipsum dolor sit amet. Data Data Data

 

 

Source Code
 



<table class="lined">
	<caption>&quot;Description Cell&quot; example - with one header per row</caption>
    
    <colgroup span="2" /><colgroup span="3" />
    
    <thead>
    	<tr>
            <th>Item</th>
            <th>Description</th>
            <th>Col 1</th>
            <th>Col 2</th>
		    <th>Col 3</th>
    	</tr>
    </thead>
    
    <tbody>
    	<tr>
            <th>Heading&nbsp;1</th>
            <td>Lorem ipsum dolor sit amet.</td>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Heading&nbsp;2</th>
            <td>Lorem ipsum dolor sit amet.</td>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Heading&nbsp;3</th>
            <td>Lorem ipsum dolor sit amet.</td>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Heading&nbsp;4</th>
            <td>Lorem ipsum dolor sit amet.</td>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Heading&nbsp;5</th>
            <td>Lorem ipsum dolor sit amet.</td>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>
        <tr>
            <th>Heading&nbsp;6</th>
            <td>Lorem ipsum dolor sit amet.</td>
            <td>Data</td>
            <td>Data</td>
            <td>Data</td>
        </tr>

    </tbody>
</table>

 

 

 

By using that technique, that create the possibility for a table parser to separate the real data vs descriptive information.

Conclusion

Now you know how to add key and descriptive cell to your table. In case of you might be interrested, here a snipped of the javascript table parser that make a distinction between a descriptive cell and a key cell. This are only to show quicly how it’s programaticly possible to understand the above theory.

 


	// Parser the colgroup header section
	var headerColgroup = undefined;
	
	// If an cell header exist in that row....
	if(lastHeadingColPos){
		var headingRowCell = [];
		var rowheader = undefined; // This are the lowest cell header level for this row
		var colKeyCell = [];
		
		for(i=0; i<lastHeadingColPos; i++){

			// Check for description cell or key cell
			if(row.cell[i].elem.nodeName.toLowerCase() == "td"){
				
				if(!row.cell[i].type && row.cell[i-1] && !(row.cell[i-1].descCell) && row.cell[i-1].type == 1 && row.cell[i-1].height == row.cell[i].height){
					row.cell[i].type = 5; // Update the cell type to "Descriptive"
					row.cell[i-1].descCell = row.cell[i];
					
					if(!row.desccell){row.desccell = [];}
					row.desccell.push(row.cell[i]);

				}
				
				// Add this cell in the key cell collection for future analysis
				if(!row.cell[i].type){
					colKeyCell.push(row.cell[i]);
				}
			}
			
			// Set for the most appropriate header that can represent this row
			if(row.cell[i].elem.nodeName.toLowerCase() == "th"){
				row.cell[i].type = 1; // Mark the cell to be an header cell
				if(rowheader && rowheader.uid != row.cell[i].uid){
					if(rowheader.height > row.cell[i].height){
						
						// The current cell are a child of the previous rowheader 
						if(!rowheader.subheader){
							rowheader.subheader = [];
							rowheader.isgroup = true;
						}
						rowheader.subheader.push(row.cell[i]);
						
						// Change the current row header
						rowheader = row.cell[i];
						headingRowCell.push(row.cell[i]);
						
					} else {
						// This case are either paralel heading of growing header, this are an error.
						if(rowheader.height == row.cell[i].height){
							errorTrigger('You can not have paralel row heading, do a cell merge to fix this');
						} else {
							errorTrigger('For a data row, the heading hiearchy need to be Generic to the specific');
						}
					}
				} 
				
				// Initial rowheader reference
				if(!rowheader){
					rowheader = row.cell[i];
					headingRowCell.push(row.cell[i]);
				}
				
				// Associate key cell
				$.each(colKeyCell, function(){
					if(!(this.type) && !(row.cell[i].key) && this.height == row.cell[i].height){
						this.type = 4;
						row.cell[i].key = this;
						if(!row.keycell){row.keycell = [];}
						row.keycell.push(this);
					}
				});
			}
		}
		
		// All the cell that have no "type" in the colKeyCell collection are problematic cells;
		$.each(colKeyCell, function(){
			if(!(this.type)){
				errorTrigger('You have a problematic cell, in your colgroup heading, that can not be understood by the parser');
				if(!row.errorcell){row.errorcell = [];}
				row.errorcell.push(this);
			}
		});
		row.headerset = headingRowCell;
		row.header = rowheader;
		
	} else {
		// There are no colgroup header,
		lastHeadingColPos = 0;
	}


Enjoy !! Don’t hesitate to leave a comments or contact me.

Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *