HiveBrain v1.2.0
Get Started
← Back to all entries
patternhtmlModerate

Best way to construct a semantic HTML table?

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
tablewayconstructsemantichtmlbest

Problem

I have to do a table like this one:

+-------+-------+-------+-------+-------+-------+
|         th 1          | th 2  | th 3  | th 4  |
+-------+-------+-------+-------+-------+-------+
|       |       |       | td 1  | td 2  | td 3  |
|       |       | th 7  +-------+-------+-------+
|       |       |       | td 4  | td 5  | td 6  |
|       | th 6  +-------+-------+-------+-------+
|       |       |       | td 7  | td 8  | td 9  |
|       |       | th 8  +-------+-------+-------+
|       |       |       | td 10 | td 11 | td 12 |
| th 5  +-------+-------+-------+-------+-------+
|       |       |       | td 13 | td 14 | td 15 |
|       |       | th 10 +-------+-------+-------+
|       |       |       | td 16 | td 17 | td 18 |
|       | th 9  +-------+-------+-------+-------+
|       |       |       | td 19 | td 20 | td 21 |
|       |       | th 11 +-------+-------+-------+
|       |       |       | td 22 | td 23 | td 24 |
+-------+-------+-------+-------+-------+-------+


The way I'm doing it right now is


    
        
            th 1
            th 2
            th 3
            th 4
                    
    
     
         
             th 5
             th 6
             th 7
             td 1
             td 2
             td 3
         
         
             td 4
             td 5
             td 6
         
         
             th 8
             td 7
             td 8
             td 9
         
         
             td 10
             td 11
             td 12
         
         
             th 9
             th 10
             td 13
             td 14
             td 15
         
         
             td 16
             td 17
             td 18
         
         
             th 11
             td 19
             td 20
             td 21
         
         
             22
             23
             24
         
     
 


What I want to know is if there is another, cleaner way to construct the same structure, like having the td i

Solution

I can't fault your tags at all. The only problem is that due to your table being quite complex, assistive technology may not be able to figure out the structure of your table.

I was going to recommend using scope but according to W3C there are some inconsistency issues.


The row and col values of the scope attribute are currently supported
to a large extent by most current versions of JAWS. However, there are
still some problems and WindowEyes support for scope is inconsistent.
The same is true for Japanese versions of these screen readers.
Versions of JAWS prior to version 5 and older versions of Window-Eyes
have inconsistent support for scope.

Using scope would look like this, with scope="col" in all ` elements in the first row and scope="row" for all other elements.


    
        
            th 1
            th 2
            th 3
            th 4
                    
    
    
        
            th 5
            th 6
            th 7
            td 1
            td 2
            td 3
        
        
            td 4
            td 5
            td 6
        
        
            th 8
            td 7
            td 8
            td 9
        
        
            td 10
            td 11
            td 12
        
        
            th 9
            th 10
            td 13
            td 14
            td 15
        
        
            td 16
            td 17
            td 18
        
        
            th 11
            td 19
            td 20
            td 21
        
        
            td 22
            td 23
            td 24
        
    


JSFiddle for scope method

This is W3C's recommendation:


At the current time, those who want to ensure consistent support
across Assistive Technologies for tables where the headers are not in
the first row/column may want to use the technique for complex tables
H43: Using id and headers attributes to associate data cells with
header cells in data tables. For simple tables that have headers in
the first column or row we recommend the use of the th and td
elements.

Let me just start off by saying this is a complete pain in order to be completely accessibly and scope will probably be fine in most cases. Here is the table using the
id/header method (shudder):


    
        
            th 1
            th 2
            th 3
            th 4
                    
    
    
        
            th 5
            th 6
            th 7
            td 1
            td 2
            td 3
        
        
            td 4
            td 5
            td 6
        
        
            th 8
            td 7
            td 8
            td 9
        
        
            td 10
            td 11
            td 12
        
        
            th 9
            th 10
            td 13
            td 14
            td 15
        
        
            td 16
            td 17
            td 18
        
        
            th 11
            td 19
            td 20
            td 21
        
        
            td 22
            td 23
            td 24
        
    


JSFiddle for id/headers

What is comes down to in the end in my opinion is an accessible solution that is also maintainable in the back end. Realistically JAWS and WindowEyes will eventually fix up their bugs and using
scope will be fine even for tables as complex as this. Unless you expect many users to use assistive technologies and require strict adherence to WCAG, go with scope. Markup needs to be beautiful too :)

There is also the
` element which is relevant but support for it isn't great currently.

Code Snippets

<table>
    <thead>
        <tr>
            <th colspan="3" scope="col">th 1</th>
            <th scope="col">th 2</th>
            <th scope="col">th 3</th>
            <th scope="col">th 4</th>
        </tr>            
    </thead>
    <tbody>
        <tr>
            <th rowspan="8" scope="row">th 5</th>
            <th rowspan="4" scope="row">th 6</th>
            <th rowspan="2" scope="row">th 7</th>
            <td>td 1</td>
            <td>td 2</td>
            <td>td 3</td>
        </tr>
        <tr>
            <td>td 4</td>
            <td>td 5</td>
            <td>td 6</td>
        </tr>
        <tr>
            <th rowspan="2" scope="row">th 8</th>
            <td>td 7</td>
            <td>td 8</td>
            <td>td 9</td>
        </tr>
        <tr>
            <td>td 10</td>
            <td>td 11</td>
            <td>td 12</td>
        </tr>
        <tr>
            <th rowspan="4" scope="row">th 9</th>
            <th rowspan="2" scope="row">th 10</th>
            <td>td 13</td>
            <td>td 14</td>
            <td>td 15</td>
        </tr>
        <tr>
            <td>td 16</td>
            <td>td 17</td>
            <td>td 18</td>
        </tr>
        <tr>
            <th rowspan="2" scope="row">th 11</th>
            <td>td 19</td>
            <td>td 20</td>
            <td>td 21</td>
        </tr>
        <tr>
            <td>td 22</td>
            <td>td 23</td>
            <td>td 24</td>
        </tr>
    </tbody>
</table>
<table>
    <thead>
        <tr>
            <th colspan="3" id="th1">th 1</th>
            <th id="th2">th 2</th>
            <th id="th3">th 3</th>
            <th id="th4">th 4</th>
        </tr>            
    </thead>
    <tbody>
        <tr>
            <th rowspan="8" id="th5" headers="th1">th 5</th>
            <th rowspan="4" id="th6" headers="th1 th5">th 6</th>
            <th rowspan="2" id="th7" headers="th1 th5 th6">th 7</th>
            <td headers="th2 th5 th6 th7">td 1</td>
            <td headers="th3 th5 th6 th7">td 2</td>
            <td headers="th4 th5 th6 th7">td 3</td>
        </tr>
        <tr>
            <td headers="th2 th5 th6 th7">td 4</td>
            <td headers="th3 th5 th6 th7">td 5</td>
            <td headers="th4 th5 th6 th7">td 6</td>
        </tr>
        <tr>
            <th rowspan="2" id="th8" headers="th1 th5 th6">th 8</th>
            <td headers="th2 th5 th6 th8">td 7</td>
            <td headers="th3 th5 th6 th8">td 8</td>
            <td headers="th4 th5 th6 th8">td 9</td>
        </tr>
        <tr>
            <td headers="th2 th5 th6 th8">td 10</td>
            <td headers="th3 th5 th6 th8">td 11</td>
            <td headers="th4 th5 th6 th8">td 12</td>
        </tr>
        <tr>
            <th rowspan="4" id="th9" headers="th1 th5">th 9</th>
            <th rowspan="2" id="th10" headers="th1 th5 th9">th 10</th>
            <td headers="th2 th5 th9 th10">td 13</td>
            <td headers="th3 th5 th9 th10">td 14</td>
            <td headers="th4 th5 th9 th10">td 15</td>
        </tr>
        <tr>
            <td headers="th2 th5 th9 th10">td 16</td>
            <td headers="th3 th5 th9 th10">td 17</td>
            <td headers="th4 th5 th9 th10">td 18</td>
        </tr>
        <tr>
            <th rowspan="2" id="th11" headers="th1 th5 th9">th 11</th>
            <td headers="th2 th5 th9 th11">td 19</td>
            <td headers="th3 th5 th9 th11">td 20</td>
            <td headers="th4 th5 th9 th11">td 21</td>
        </tr>
        <tr>
            <td headers="th2 th5 th9 th11">td 22</td>
            <td headers="th3 th5 th9 th11">td 23</td>
            <td headers="th4 th5 th9 th11">td 24</td>
        </tr>
    </tbody>
</table>

Context

StackExchange Code Review Q#17936, answer score: 12

Revisions (0)

No revisions yet.