W3C

HTML 5

A vocabulary and associated APIs for HTML and XHTML

← 4.8.11 The canvas elementTable of contents4.10 Forms →

4.9 Tabular data

4.9.1 Introduction

This section is non-normative.

...examples, how to write tables accessibly, a brief mention of the table model, etc...

4.9.2 The table element

Categories
Flow content.
Contexts in which this element may be used:
Where flow content is expected.
Content model:
In this order: optionally a caption element, followed by either zero or more colgroup elements, followed optionally by a thead element, followed optionally by a tfoot element, followed by either zero or more tbody elements or one or more tr elements, followed optionally by a tfoot element (but there can only be one tfoot element child in total).
Content attributes:
Global attributes
summary
DOM interface:
interface HTMLTableElement : HTMLElement {
           attribute HTMLTableCaptionElement caption;
  HTMLElement createCaption();
  void deleteCaption();
           attribute HTMLTableSectionElement tHead;
  HTMLElement createTHead();
  void deleteTHead();
           attribute HTMLTableSectionElement tFoot;
  HTMLElement createTFoot();
  void deleteTFoot();
  readonly attribute HTMLCollection tBodies;
  HTMLElement createTBody();
  readonly attribute HTMLCollection rows;
  HTMLElement insertRow(optional in long index);
  void deleteRow(in long index);
  attribute DOMString summary;
};

The table element represents data with more than one dimension, in the form of a table.

The table element takes part in the table model.

Tables must not be used as layout aids. Historically, some Web authors have misused tables in HTML as a way to control their page layout. This usage is non-conforming, because tools attempting to extract tabular data from such documents would obtain very confusing results. In particular, users of accessibility tools like screen readers are likely to find it very difficult to navigate pages with tables used for layout.

There are a variety of alternatives to using HTML tables for layout, primarily using CSS positioning and the CSS table model.

User agents that do table analysis on arbitrary content are encouraged to find heuristics to determine which tables actually contain data and which are merely being used for layout. This specification does not define a precise heuristic.

The status of the summary attribute is an open issue

The summary attribute provides a summary of the table's purpose and structure for user agents rendering to non-visual media such as speech and Braille.

Summary is one way to provide explanatory information about tables that consist of more than just a grid of cells with headers in the first row and headers in the first column. Such explanatory information should introduce the purpose of the table, outline its basic cell structure, highlight any trends or patterns, and generally teach the user how to use the table. The content of summary [should | must ] not be displayed by visual user agents, and should be used by authors to provide infomration about relationships between data elements that are obvious to users who can see the two-dimensional layout of the table, but would be difficult to determine for users who cannot see the table. The information provided by the summary is needed by users who cannot see the table, but would usually be redundant for those who can. For tables where the relationships are not obvious to users who can see the layout, or in other situations where text describing the structure of the table might be useful to sighted users as well as users of screen-readers and Braille devices, it is better to describe the structure using the a caption, legend, or surrounding text instead of, or in addition to, summary. This must be done in a way that is associated with the table via markup, such that user agents and assistive technology can programmatically determine the relationship. When using summary in combination with another technique, authors must not use the duplicate text, but instead use summary for the parts of the description that are only useful to users who cannot see the table.User agents [must | should] expose summary text in the accessibility API on their platform as specified in the Mappings from HTML to Platform APIs document [note: This document is still under development and does not yet have a stable URL. It will have one before last call]

A well-written summary can provide a verbal map that helps someone using a screen reader navigate the data more efficiently:

[@@insert table code sample from Matt May here]

<table summary="The table is divided into six columns: Map number, 
  Date, Area or stream with flooding, Reported deaths, Approximate costs 
  (uninflated), and Comments. The rows are grouped by flood types into six 
  subcategories:  Regional flood, Flash flood, Ice-jam flood, Storm-surge flood, 
  Dam-failure flood and Mudflow flood." >

The preceding code summarizes the table with the following information: The number and titles of the column headings The stubhead ("The rows are...") and subheadings are key information.

The following table has an unusual layout which will not be obvious to many users who can see it. It might benefit from a visible description explaining to the way the table is laid out, something like "Characteristics are given in the second column, with the negative side in the left column and the positive side in the right column". In this case, it is best to describe the table in visible text. The text must be marked up in such a way that assistive technologies can determine programmatically that it is a description for the table.

Characteristics with positive and negative sides
Negative Characteristic Positive
Sad Mood Happy
Failing Grade Passing

There are a variety of ways to include this information, such as:

In prose, surrounding the table. When using this approach, authors must use the aria-describedby or aria-labeledby attribute to link the prose to the table in a way that can be programmatically determined by assistive technology and other user agents.  [note: aria will eventually be integrated into the HTML 5 spec.  Once that happens, this should link to the description of these attributes]
<p id="desc">In the following table, characteristics are given in the second
column, with the negative side in the left column and the positive
side in the right column.</p>
<table aria-described-by="desc">
 <caption>Characteristics with positive and negative sides</caption>
 <thead>
  <tr>
   <th id="n"> Negative
   <th> Characteristic
   <th> Positive
 <tbody>
  <tr>
   <td headers="n r1"> Sad
   <th id="r1"> Mood
   <td> Happy
  <tr>
   <td headers="n r2"> Failing
   <th id="r2"> Grade
   <td> Passing
</table>
In the table's caption
<table>
 <caption>
  <strong>Characteristics with positive and negative sides.</strong>
  <p>Characteristics are given in the second column, with the
  negative side in the left column and the positive side in the right
  column.</p>
 </caption>
 <thead>
  <tr>
   <th id="n"> Negative
   <th> Characteristic
   <th> Positive
 <tbody>
  <tr>
   <td headers="n r1"> Sad
   <th id="r1"> Mood
   <td> Happy
  <tr>
   <td headers="n r2"> Failing
   <th id="r2"> Grade
   <td> Passing
</table>
In the table's caption, in a details element
<table>
 <caption>
  <strong>Characteristics with positive and negative sides.</strong>
  <details>
   <legend>Help</legend>
   <p>Characteristics are given in the second column, with the
   negative side in the left column and the positive side in the right
   column.</p>
  </details>
 </caption>
 <thead>
  <tr>
   <th id="n"> Negative
   <th> Characteristic
   <th> Positive
 <tbody>
  <tr>
   <td headers="n r1"> Sad
   <th id="r1"> Mood
   <td> Happy
  <tr>
   <td headers="n r2"> Failing
   <th id="r2"> Grade
   <td> Passing
</table>
Next to the table, in the same figure [note: once browser and AT support figure, this is probably programmatically determinable under WCAG. Mapping it to platform accessibility APIs would be hard though. It may also need aria-describedby]
<figure>
 <legend>Characteristics with positive and negative sides</legend>
 <p>Characteristics are given in the second
 column, with the negative side in the left column and the positive
 side in the right column.</p>
 <table>
  <thead>
   <tr>
    <th id="n"> Negative
    <th> Characteristic
    <th> Positive
  <tbody>
   <tr>
    <td headers="n r1"> Sad
    <th id="r1"> Mood
    <td> Happy
   <tr>
    <td headers="n r2"> Failing
    <th id="r2"> Grade
    <td> Passing
 </table>
<figure>
Next to the table, in a figure's legend
<figure>
 <legend>
  <strong>Characteristics with positive and negative sides</strong>
  <p>Characteristics are given in the second
  column, with the negative side in the left column and the positive
  side in the right column.</p>
 </legend>
 <table>
  <thead>
   <tr>
    <th id="n"> Negative
    <th> Characteristic
    <th> Positive
  <tbody>
   <tr>
    <td headers="n r1"> Sad
    <th id="r1"> Mood
    <td> Happy
   <tr>
    <td headers="n r2"> Failing
    <th id="r2"> Grade
    <td> Passing
 </table>
<figure>
table . caption [ = value ]

Returns the table's caption element.

Can be set, to replace the caption element. If the new value is not a caption element, throws a HIERARCHY_REQUEST_ERR exception.

caption = table . createCaption()

Ensures the table has a caption element, and returns it.

table . deleteCaption()

Ensures the table does not have a caption element.

table . summary [ = value ]

Returns the table's summary attribute.

Can be set, to replace the summary attribute.

[Note: is it better just to use the normal DOM attribute syntax here?]

summary = table . createSummary()

Ensures the table has a summary attribute, and returns it.

table . deleteSummary()

Ensures the table does not have a summary attribute.

table . tHead [ = value ]

Returns the table's thead element.

Can be set, to replace the thead element. If the new value is not a thead element, throws a HIERARCHY_REQUEST_ERR exception.

thead = table . createTHead()

Ensures the table has a thead element, and returns it.

table . deleteTHead()

Ensures the table does not have a thead element.

table . tFoot [ = value ]

Returns the table's tfoot element.

Can be set, to replace the tfoot element. If the new value is not a tfoot element, throws a HIERARCHY_REQUEST_ERR exception.

tfoot = table . createTFoot()

Ensures the table has a tfoot element, and returns it.

table . deleteTFoot()

Ensures the table does not have a tfoot element.

table . tBodies

Returns an HTMLCollection of the tbody elements of the table.

tbody = table . createTBody()

Creates a tbody element, inserts it into the table, and returns it.

table . rows

Returns an HTMLCollection of the tr elements of the table.

tr = table . insertRow(index)

Creates a tr element, along with a tbody if required, inserts them into the table at the position given by the argument, and returns the tr.

The position is relative to the rows in the table. The index −1 is equivalent to inserting at the end of the table.

If the given position is less than −1 or greater than the number of rows, throws an INDEX_SIZE_ERR exception.

table . deleteRow(index)

Removes the tr element with the given position in the table.

The position is relative to the rows in the table. The index −1 is equivalent to deleting the last row of the table.

If the given position is less than −1 or greater than the index of the last row, or if there are no rows, throws an INDEX_SIZE_ERR exception.

The caption DOM attribute must return, on getting, the first caption element child of the table element, if any, or null otherwise. On setting, if the new value is a caption element, the first caption element child of the table element, if any, must be removed, and the new value must be inserted as the first node of the table element. If the new value is not a caption element, then a HIERARCHY_REQUEST_ERR DOM exception must be raised instead.

The createCaption() method must return the first caption element child of the table element, if any; otherwise a new caption element must be created, inserted as the first node of the table element, and then returned.

The deleteCaption() method must remove the first caption element child of the table element, if any.

The tHead DOM attribute must return, on getting, the first thead element child of the table element, if any, or null otherwise. On setting, if the new value is a thead element, the first thead element child of the table element, if any, must be removed, and the new value must be inserted immediately before the first element in the table element that is neither a caption element nor a colgroup element, if any, or at the end of the table otherwise. If the new value is not a thead element, then a HIERARCHY_REQUEST_ERR DOM exception must be raised instead.

The createTHead() method must return the first thead element child of the table element, if any; otherwise a new thead element must be created and inserted immediately before the first element in the table element that is neither a caption element nor a colgroup element, if any, or at the end of the table otherwise, and then that new element must be returned.

The deleteTHead() method must remove the first thead element child of the table element, if any.

The tFoot DOM attribute must return, on getting, the first tfoot element child of the table element, if any, or null otherwise. On setting, if the new value is a tfoot element, the first tfoot element child of the table element, if any, must be removed, and the new value must be inserted immediately before the first element in the table element that is neither a caption element, a colgroup element, nor a thead element, if any, or at the end of the table if there are no such elements. If the new value is not a tfoot element, then a HIERARCHY_REQUEST_ERR DOM exception must be raised instead.

The createTFoot() method must return the first tfoot element child of the table element, if any; otherwise a new tfoot element must be created and inserted immediately before the first element in the table element that is neither a caption element, a colgroup element, nor a thead element, if any, or at the end of the table if there are no such elements, and then that new element must be returned.

The deleteTFoot() method must remove the first tfoot element child of the table element, if any.

The tBodies attribute must return an HTMLCollection rooted at the table node, whose filter matches only tbody elements that are children of the table element.

The createTBody() method must create a new tbody element, insert it immediately after the last tbody element in the table element, if any, or at the end of the table element if the table element has no tbody element children, and then must return the new tbody element.

The rows attribute must return an HTMLCollection rooted at the table node, whose filter matches only tr elements that are either children of the table element, or children of thead, tbody, or tfoot elements that are themselves children of the table element. The elements in the collection must be ordered such that those elements whose parent is a thead are included first, in tree order, followed by those elements whose parent is either a table or tbody element, again in tree order, followed finally by those elements whose parent is a tfoot element, still in tree order.

The behavior of the insertRow(index) method depends on the state of the table. When it is called, the method must act as required by the first item in the following list of conditions that describes the state of the table and the index argument:

If index is less than −1 or greater than the number of elements in rows collection:
The method must raise an INDEX_SIZE_ERR exception.
If the rows collection has zero elements in it, and the table has no tbody elements in it:
The method must create a tbody element, then create a tr element, then append the tr element to the tbody element, then append the tbody element to the table element, and finally return the tr element.
If the rows collection has zero elements in it:
The method must create a tr element, append it to the last tbody element in the table, and return the tr element.
If index is missing, equal to −1, or equal to the number of items in rows collection:
The method must create a tr element, and append it to the parent of the last tr element in the rows collection. Then, the newly created tr element must be returned.
Otherwise:
The method must create a tr element, insert it immediately before the indexth tr element in the rows collection, in the same parent, and finally must return the newly created tr element.

When the deleteRow(index) method is called, the user agent must run the following steps:

  1. If index is equal to −1, then index must be set to the number if items in the rows collection, minus one.

  2. Now, if index is less than zero, or greater than or equal to the number of elements in the rows collection, the method must instead raise an INDEX_SIZE_ERR exception, and these steps must be aborted.

  3. Otherwise, the method must remove the indexth element in the rows collection from its parent.

4.9.3 The caption element

Categories
None.
Contexts in which this element may be used:
As the first element child of a table element.
Content model:
Flow content, but with no descendant table elements.
Content attributes:
Global attributes
DOM interface:
interface HTMLTableCaptionElement : HTMLElement {};

The caption element represents the title of the table that is its parent, if it has a parent and that is a table element.

The caption element takes part in the table model.

When a table element is in a figure element alone but for the figure's legend, the caption element should be omitted in favor of the legend.

A caption can introduce context for a table, making it significantly easier to understand.

Consider, for instance, the following table:

1 2 3 4 5 6
1 2 3 4 5 6 7
2 3 4 5 6 7 8
3 4 5 6 7 8 9
4 5 6 7 8 9 10
5 6 7 8 9 10 11
6 7 8 9 10 11 12

In the abstract, this table is not clear. However, with a caption giving the table's number (for reference in the main prose) and explaining its use, it makes more sense:

<caption>
<p>Table 1.
<p>This table shows the total score obtained from rolling two
six-sided dice. The first row represents the value of the first die,
the first column the value of the second die. The total is given in
the cell that corresponds to the values of the two dice.
</caption>

This provides the user with more context:

Table 1.

This table shows the total score obtained from rolling two six-sided dice. The first row represents the value of the first die, the first column the value of the second die. The total is given in the cell that corresponds to the values of the two dice.

1 2 3 4 5 6
1 2 3 4 5 6 7
2 3 4 5 6 7 8
3 4 5 6 7 8 9
4 5 6 7 8 9 10
5 6 7 8 9 10 11
6 7 8 9 10 11 12

4.9.4 The colgroup element

Categories
None.
Contexts in which this element may be used:
As a child of a table element, after any caption elements and before any thead, tbody, tfoot, and tr elements.
Content model:
Zero or more col elements.
Content attributes:
Global attributes
span
DOM interface:
interface HTMLTableColElement : HTMLElement {
           attribute unsigned long span;
};

The colgroup element represents a group of one or more columns in the table that is its parent, if it has a parent and that is a table element.

If the colgroup element contains no col elements, then the element may have a span content attribute specified, whose value must be a valid non-negative integer greater than zero.

The colgroup element and its span attribute take part in the table model.

The span DOM attribute must reflect the respective content attribute of the same name. The value must be limited to only positive non-zero numbers.

4.9.5 The col element

Categories
None.
Contexts in which this element may be used:
As a child of a colgroup element that doesn't have a span attribute.
Content model:
Empty.
Content attributes:
Global attributes
span
DOM interface:

HTMLTableColElement, same as for colgroup elements. This interface defines one member, span.

If a col element has a parent and that is a colgroup element that itself has a parent that is a table element, then the col element represents one or more columns in the column group represented by that colgroup.

The element may have a span content attribute specified, whose value must be a valid non-negative integer greater than zero.

The col element and its span attribute take part in the table model.

The span DOM attribute must reflect the content attribute of the same name. The value must be limited to only positive non-zero numbers.

4.9.6 The tbody element

Categories
None.
Contexts in which this element may be used:
As a child of a table element, after any caption, colgroup, and thead elements, but only if there are no tr elements that are children of the table element.
Content model:
Zero or more tr elements
Content attributes:
Global attributes
DOM interface:
interface HTMLTableSectionElement : HTMLElement {
  readonly attribute HTMLCollection rows;
  HTMLElement insertRow(optional in long index);
  void deleteRow(in long index);
};

The HTMLTableSectionElement interface is also used for thead and tfoot elements.

The tbody element represents a block of rows that consist of a body of data for the parent table element, if the tbody element has a parent and it is a table.

The tbody element takes part in the table model.

tbody . rows

Returns an HTMLCollection of the tr elements of the table section.

tr = tbody . insertRow( [ index ] )

Creates a tr element, inserts it into the table section at the position given by the argument, and returns the tr.

The position is relative to the rows in the table section. The index −1, which is the default if the argument is omitted, is equivalent to inserting at the end of the table section.

If the given position is less than −1 or greater than the number of rows, throws an INDEX_SIZE_ERR exception.

tbody . deleteRow(index)

Removes the tr element with the given position in the table section.

The position is relative to the rows in the table section. The index −1 is equivalent to deleting the last row of the table section.

If the given position is less than −1 or greater than the index of the last row, or if there are no rows, throws an INDEX_SIZE_ERR exception.

The rows attribute must return an HTMLCollection rooted at the element, whose filter matches only tr elements that are children of the element.

The insertRow(index) method must, when invoked on an element table section, act as follows:

If index is less than −1 or greater than the number of elements in the rows collection, the method must raise an INDEX_SIZE_ERR exception.

If index is missing, equal to −1, or equal to the number of items in the rows collection, the method must create a tr element, append it to the element table section, and return the newly created tr element.

Otherwise, the method must create a tr element, insert it as a child of the table section element, immediately before the indexth tr element in the rows collection, and finally must return the newly created tr element.

The deleteRow(index) method must remove the indexth element in the rows collection from its parent. If index is less than zero or greater than or equal to the number of elements in the rows collection, the method must instead raise an INDEX_SIZE_ERR exception.

4.9.7 The thead element

Categories
None.
Contexts in which this element may be used:
As a child of a table element, after any caption, and colgroup elements and before any tbody, tfoot, and tr elements, but only if there are no other thead elements that are children of the table element.
Content model:
Zero or more tr elements
Content attributes:
Global attributes
DOM interface:
HTMLTableSectionElement, as defined for tbody elements.

The thead element represents the block of rows that consist of the column labels (headers) for the parent table element, if the thead element has a parent and it is a table.

The thead element takes part in the table model.

4.9.8 The tfoot element

Categories
None.
Contexts in which this element may be used:
As a child of a table element, after any caption, colgroup, and thead elements and before any tbody and tr elements, but only if there are no other tfoot elements that are children of the table element.
As a child of a table element, after any caption, colgroup, thead, tbody, and tr elements, but only if there are no other tfoot elements that are children of the table element.
Content model:
Zero or more tr elements
Content attributes:
Global attributes
DOM interface:
HTMLTableSectionElement, as defined for tbody elements.

The tfoot element represents the block of rows that consist of the column summaries (footers) for the parent table element, if the tfoot element has a parent and it is a table.

The tfoot element takes part in the table model.

4.9.9 The tr element

Categories
None.
Contexts in which this element may be used:
As a child of a thead element.
As a child of a tbody element.
As a child of a tfoot element.
As a child of a table element, after any caption, colgroup, and thead elements, but only if there are no tbody elements that are children of the table element.
Content model:
When the parent node is a thead element: Zero or more th elements
Otherwise: Zero or more td or th elements
Content attributes:
Global attributes
DOM interface:
interface HTMLTableRowElement : HTMLElement {
  readonly attribute long rowIndex;
  readonly attribute long sectionRowIndex;
  readonly attribute HTMLCollection cells;
  HTMLElement insertCell(optional in long index);
  void deleteCell(in long index);
};

The tr element represents a row of cells in a table.

The tr element takes part in the table model.

tr . rowIndex

Returns the position of the row in the table's rows list.

Returns −1 if the element isn't in a table.

tr . sectionRowIndex

Returns the position of the row in the table section's rows list.

Returns −1 if the element isn't in a table section.

tr . cells

Returns an HTMLCollection of the td and th elements of the row.

cell = tr . insertCell( [ index ] )

Creates a td element, inserts it into the table row at the position given by the argument, and returns the td.

The position is relative to the cells in the row. The index −1, which is the default if the argument is omitted, is equivalent to inserting at the end of the row.

If the given position is less than −1 or greater than the number of cells, throws an INDEX_SIZE_ERR exception.

tr . deleteCell(index)

Removes the td or th element with the given position in the row.

The position is relative to the cells in the row. The index −1 is equivalent to deleting the last cell of the row.

If the given position is less than −1 or greater than the index of the last cell, or if there are no cells, throws an INDEX_SIZE_ERR exception.

The rowIndex attribute must, if the element has a parent table element, or a parent tbody, thead, or tfoot element and a grandparent table element, return the index of the tr element in that table element's rows collection. If there is no such table element, then the attribute must return −1.

The sectionRowIndex attribute must, if the element has a parent table, tbody, thead, or tfoot element, return the index of the tr element in the parent element's rows collection (for tables, that's the rows collection; for table sections, that's the rows collection). If there is no such parent element, then the attribute must return −1.

The cells attribute must return an HTMLCollection rooted at the tr element, whose filter matches only td and th elements that are children of the tr element.

The insertCell(index) method must act as follows:

If index is less than −1 or greater than the number of elements in the cells collection, the method must raise an INDEX_SIZE_ERR exception.

If index is missing, equal to −1, or equal to the number of items in cells collection, the method must create a td element, append it to the tr element, and return the newly created td element.

Otherwise, the method must create a td element, insert it as a child of the tr element, immediately before the indexth td or th element in the cells collection, and finally must return the newly created td element.

The deleteCell(index) method must remove the indexth element in the cells collection from its parent. If index is less than zero or greater than or equal to the number of elements in the cells collection, the method must instead raise an INDEX_SIZE_ERR exception.

4.9.10 The td element

Categories
Sectioning root.
Contexts in which this element may be used:
As a child of a tr element.
Content model:
Flow content.
Content attributes:
Global attributes
colspan
rowspan
headers
DOM interface:
interface HTMLTableDataCellElement : HTMLTableCellElement {};

The td element represents a data cell in a table.

The td element and its colspan, rowspan, and headers attributes take part in the table model.

4.9.11 The th element

Categories
None.
Contexts in which this element may be used:
As a child of a tr element.
Content model:
Phrasing content.
Content attributes:
Global attributes
colspan
rowspan
headers
scope
DOM interface:
interface HTMLTableHeaderCellElement : HTMLTableCellElement {
           attribute DOMString scope;
};

The th element represents a header cell in a table.

The th element may have a scope content attribute specified. The scope attribute is an enumerated attribute with five states, four of which have explicit keywords:

The row keyword, which maps to the row state
The row state means the header cell applies to some of the subsequent cells in the same row(s).
The col keyword, which maps to the column state
The column state means the header cell applies to some of the subsequent cells in the same column(s).
The rowgroup keyword, which maps to the row group state
The row group state means the header cell applies to all the remaining cells in the row group. A th element's scope attribute must not be in the row group state if the element is not anchored in a row group.
The colgroup keyword, which maps to the column group state
The column group state means the header cell applies to all the remaining cells in the column group. A th element's scope attribute must not be in the column group state if the element is not anchored in a column group.
The auto state
The auto state makes the header cell apply to a set of cells selected based on context.

The scope attribute's missing value default is the auto state.

The th element and its colspan, rowspan, headers, and scope attributes take part in the table model.

The scope DOM attribute must reflect the content attribute of the same name.

The following example shows how the scope attribute's rowgroup value affects which data cells a header cell applies to.

Here is a markup fragment showing a table:

<table>
 <thead>
  <tr> <th> ID <th> Measurement <th> Average <th> Maximum
 <tbody>
  <tr> <td> <th scope=rowgroup> Cats <td> <td>
  <tr> <td> 93 <td> Legs <td> 3.5 <td> 4
  <tr> <td> 10 <td> Tails <td> 1 <td> 1
 <tbody>
  <tr> <td> <th scope=rowgroup> English speakers <td> <td>
  <tr> <td> 32 <td> Legs <td> 2.67 <td> 4
  <tr> <td> 35 <td> Tails <td> 0.33 <td> 1
</table>

This would result in the following table:

ID Measurement Average Maximum
Cats
93 Legs 3.5 4
10 Tails 1 1
English speakers
32 Legs 2.67 4
35 Tails 0.33 1

The headers in the first row all apply directly down to the rows in their column.

The headers with the explicit scope attributes apply to all the cells in their row group other than the cells in the first column.

The remaining headers apply just to the cells to the right of them.

4.9.12 Attributes common to td and th elements

The td and th elements may have a colspan content attribute specified, whose value must be a valid non-negative integer greater than zero.

The td and th elements may also have a rowspan content attribute specified, whose value must be a valid non-negative integer.

These attributes give the number of columns and rows respectively that the cell is to span. These attributes must not be used to overlap cells, as described in the description of the table model.


The td and th element may have a headers content attribute specified. The headers attribute, if specified, must contain a string consisting of an unordered set of unique space-separated tokens, each of which must have the value of an ID of a th element taking part in the same table as the td or th element (as defined by the table model).

A th element with ID id is said to be directly targeted by all td and th elements in the same table that have headers attributes whose values include as one of their tokens the ID id. A th element A is said to be targeted by a th or td element B if either A is directly targeted by B or if there exists an element C that is itself targeted by the element B and A is directly targeted by C.

A th element must not be targeted by itself.

The colspan, rowspan, and headers attributes take part in the table model.


The td and th elements implement interfaces that inherit from the HTMLTableCellElement interface:

interface HTMLTableCellElement : HTMLElement {
           attribute unsigned long colSpan;
           attribute unsigned long rowSpan;
           attribute DOMString headers;
  readonly attribute long cellIndex;
};
cell . cellIndex

Returns the position of the cell in the row's cells list.

Returns 0 if the element isn't in a row.

The colSpan DOM attribute must reflect the content attribute of the same name. The value must be limited to only positive non-zero numbers.

The rowSpan DOM attribute must reflect the content attribute of the same name. Its default value, which must be used if parsing the attribute as a non-negative integer returns an error, is also 1.

The headers DOM attribute must reflect the content attribute of the same name.

The cellIndex DOM attribute must, if the element has a parent tr element, return the index of the cell's element in the parent element's cells collection. If there is no such parent element, then the attribute must return 0.

4.9.13 Processing model

The various table elements and their content attributes together define the table model.

A table consists of cells aligned on a two-dimensional grid of slots with coordinates (x, y). The grid is finite, and is either empty or has one or more slots. If the grid has one or more slots, then the x coordinates are always in the range 0 ≤ x < xwidth, and the y coordinates are always in the range 0 ≤ y < yheight. If one or both of xwidth and yheight are zero, then the table is empty (has no slots). Tables correspond to table elements.

A cell is a set of slots anchored at a slot (cellx, celly), and with a particular width and height such that the cell covers all the slots with coordinates (x, y) where cellx ≤ x < cellx+width and celly ≤ y < celly+height. Cells can either be data cells or header cells. Data cells correspond to td elements, and header cells correspond to th elements. Cells of both types can have zero or more associated header cells.

It is possible, in certain error cases, for two cells to occupy the same slot.

A row is a complete set of slots from x=0 to x=xwidth-1, for a particular value of y. Rows correspond to tr elements.

A column is a complete set of slots from y=0 to y=yheight-1, for a particular value of x. Columns can correspond to col elements, but in the absence of col elements are implied.

A row group is a set of rows anchored at a slot (0, groupy) with a particular height such that the row group covers all the slots with coordinates (x, y) where 0 ≤ x < xwidth and groupy ≤ y < groupy+height. Row groups correspond to tbody, thead, and tfoot elements. Not every row is necessarily in a row group.

A column group is a set of columns anchored at a slot (groupx, 0) with a particular width such that the column group covers all the slots with coordinates (x, y) where groupx ≤ x < groupx+width and 0 ≤ y < yheight. Column groups correspond to colgroup elements. Not every column is necessarily in a column group.

Row groups cannot overlap each other. Similarly, column groups cannot overlap each other.

A cell cannot cover slots that are from two or more row groups. It is, however, possible for a cell to be in multiple column groups. All the slots that form part of one cell are part of zero or one row groups and zero or more column groups.

In addition to cells, columns, rows, row groups, and column groups, tables can have a caption element associated with them. This gives the table a heading, or legend.

A table model error is an error with the data represented by table elements and their descendants. Documents must not have table model errors.

4.9.13.1 Forming a table

To determine which elements correspond to which slots in a table associated with a table element, to determine the dimensions of the table (xwidth and yheight), and to determine if there are any table model errors, user agents must use the following algorithm:

  1. Let xwidth be zero.

  2. Let yheight be zero.

  3. Let pending tfoot elements be a list of tfoot elements, initially empty.

  4. Let the table be the table represented by the table element. The xwidth and yheight variables give the table's dimensions. The table is initially empty.

  5. If the table element has no children elements, then return the table (which will be empty), and abort these steps.

  6. Associate the first caption element child of the table element with the table. If there are no such children, then it has no associated caption element.

  7. Let the current element be the first element child of the table element.

    If a step in this algorithm ever requires the current element to be advanced to the next child of the table when there is no such next child, then the user agent must jump to the step labeled end, near the end of this algorithm.

  8. While the current element is not one of the following elements, advance the current element to the next child of the table:

  9. If the current element is a colgroup, follow these substeps:

    1. Column groups: Process the current element according to the appropriate case below:

      If the current element has any col element children

      Follow these steps:

      1. Let xstart have the value of xwidth.

      2. Let the current column be the first col element child of the colgroup element.

      3. Columns: If the current column col element has a span attribute, then parse its value using the rules for parsing non-negative integers.

        If the result of parsing the value is not an error or zero, then let span be that value.

        Otherwise, if the col element has no span attribute, or if trying to parse the attribute's value resulted in an error, then let span be 1.

      4. Increase xwidth by span.

      5. Let the last span columns in the table correspond to the current column col element.

      6. If current column is not the last col element child of the colgroup element, then let the current column be the next col element child of the colgroup element, and return to the step labeled columns.

      7. Let all the last columns in the table from x=xstart to x=xwidth-1 form a new column group, anchored at the slot (xstart, 0), with width xwidth-xstart, corresponding to the colgroup element.

      If the current element has no col element children
      1. If the colgroup element has a span attribute, then parse its value using the rules for parsing non-negative integers.

        If the result of parsing the value is not an error or zero, then let span be that value.

        Otherwise, if the colgroup element has no span attribute, or if trying to parse the attribute's value resulted in an error, then let span be 1.

      2. Increase xwidth by span.

      3. Let the last span columns in the table form a new column group, anchored at the slot (xwidth-span, 0), with width span, corresponding to the colgroup element.

    2. Advance the current element to the next child of the table.

    3. While the current element is not one of the following elements, advance the current element to the next child of the table:

    4. If the current element is a colgroup element, jump to the step labeled column groups above.

  10. Let ycurrent be zero.

  11. Let the list of downward-growing cells be an empty list.

  12. Rows: While the current element is not one of the following elements, advance the current element to the next child of the table:

  13. If the current element is a tr, then run the algorithm for processing rows, advance the current element to the next child of the table, and return to the step labeled rows.

  14. Run the algorithm for ending a row group.

  15. If the current element is a tfoot, then add that element to the list of pending tfoot elements, advance the current element to the next child of the table, and return to the step labeled rows.

  16. The current element is either a thead or a tbody.

    Run the algorithm for processing row groups.

  17. Advance the current element to the next child of the table.

  18. Return to the step labeled rows.

  19. End: For each tfoot element in the list of pending tfoot elements, in tree order, run the algorithm for processing row groups.

  20. If there exists a row or column in the table the table containing only slots that do not have a cell anchored to them, then this is a table model error.

  21. Return the table.

The algorithm for processing row groups, which is invoked by the set of steps above for processing thead, tbody, and tfoot elements, is:

  1. Let ystart have the value of yheight.

  2. For each tr element that is a child of the element being processed, in tree order, run the algorithm for processing rows.

  3. If yheight > ystart, then let all the last rows in the table from y=ystart to y=yheight-1 form a new row group, anchored at the slot with coordinate (0, ystart), with height yheight-ystart, corresponding to the element being processed.

  4. Run the algorithm for ending a row group.

The algorithm for ending a row group, which is invoked by the set of steps above when starting and ending a block of rows, is:

  1. While ycurrent is less than yheight, follow these steps:

    1. Run the algorithm for growing downward-growing cells.

    2. Increase ycurrent by 1.

  2. Empty the list of downward-growing cells.

The algorithm for processing rows, which is invoked by the set of steps above for processing tr elements, is:

  1. If yheight is equal to ycurrent, then increase yheight by 1. (ycurrent is never greater than yheight.)

  2. Let xcurrent be 0.

  3. Run the algorithm for growing downward-growing cells.

  4. If the tr element being processed has no td or th element children, then increase ycurrent by 1, abort this set of steps, and return to the algorithm above.

  5. Let current cell be the first td or th element in the tr element being processed.

  6. Cells: While xcurrent is less than xwidth and the slot with coordinate (xcurrent, ycurrent) already has a cell assigned to it, increase xcurrent by 1.

  7. If xcurrent is equal to xwidth, increase xwidth by 1. (xcurrent is never greater than xwidth.)

  8. If the current cell has a colspan attribute, then parse that attribute's value, and let colspan be the result.

    If parsing that value failed, or returned zero, or if the attribute is absent, then let colspan be 1, instead.

  9. If the current cell has a rowspan attribute, then parse that attribute's value, and let rowspan be the result.

    If parsing that value failed or if the attribute is absent, then let rowspan be 1, instead.

  10. If rowspan is zero, then let cell grows downward be true, and set rowspan to 1. Otherwise, let cell grows downward be false.

  11. If xwidth < xcurrent+colspan, then let xwidth be xcurrent+colspan.

  12. If yheight < ycurrent+rowspan, then let yheight be ycurrent+rowspan.

  13. Let the slots with coordinates (x, y) such that xcurrent ≤ x < xcurrent+colspan and ycurrent ≤ y < ycurrent+rowspan be covered by a new cell c, anchored at (xcurrent, ycurrent), which has width colspan and height rowspan, corresponding to the current cell element.

    If the current cell element is a th element, let this new cell c be a header cell; otherwise, let it be a data cell.

    To establish which header cells apply to the current cell element, use the algorithm for assigning header cells described in the next section.

    If any of the slots involved already had a cell covering them, then this is a table model error. Those slots now have two cells overlapping.

  14. If cell grows downward is true, then add the tuple {c, xcurrent, colspan} to the list of downward-growing cells.

  15. Increase xcurrent by colspan.

  16. If current cell is the last td or th element in the tr element being processed, then increase ycurrent by 1, abort this set of steps, and return to the algorithm above.

  17. Let current cell be the next td or th element in the tr element being processed.

  18. Return to the step labelled cells.

When the algorithms above require the user agent to run the algorithm for growing downward-growing cells, the user agent must, for each {cell, cellx, width} tuple in the list of downward-growing cells, if any, extend the cell cell so that it also covers the slots with coordinates (x, ycurrent), where cellx ≤ x < cellx+width.

4.9.13.2 Forming relationships between data cells and header cells

Each cell can be assigned zero or more header cells. The algorithm for assigning header cells to a cell principal cell is as follows.

  1. Let header list be an empty list of cells.

  2. Let (principalx, principaly) be the coordinate of the slot to which the principal cell is anchored.

  3. If the principal cell has a headers attribute specified
    1. Take the value of the principal cell's headers attribute and split it on spaces, letting id list be the list of tokens obtained.

    2. For each token in the id list, if the first element in the Document with an ID equal to the token is a cell in the same table, and that cell is not the principal cell, then add that cell to header list.

    If principal cell does not have a headers attribute specified
    1. Let principalwidth be the width of the principal cell.

    2. Let principalheight be the height of the principal cell.

    3. For each value of y from principaly to principaly+principalheight-1, run the internal algorithm for scanning and assigning header cells, with the principal cell, the header list, the initial coordinate (principalx,y), and the increments Δx=−1 and Δy=0.

    4. For each value of x from principalx to principalx+principalwidth-1, run the internal algorithm for scanning and assigning header cells, with the principal cell, the header list, the initial coordinate (x,principaly), and the increments Δx=0 and Δy=−1.

    5. If the principal cell is anchored in a row group, then add all header cells that are row group headers and are anchored in the same row group with an x-coordinate less than or equal to principalx+principalwidth-1 and a y-coordinate less than or equal to principaly+principalheight-1 to header list.

    6. If the principal cell is anchored in a column group, then add all header cells that are column group headers and are anchored in the same column group with an x-coordinate less than or equal to principalx+principalwidth-1 and a y-coordinate less than or equal to principaly+principalheight-1 to header list.

  4. Remove all the empty cells from the header list.

  5. Remove any duplicates from the header list.

  6. Assign the headers in the header list to the principal cell.

The internal algorithm for scanning and assigning header cells, given a principal cell, a header list, an initial coordinate (initialx, initialy), and Δx and Δy increments, is as follows:

  1. Let x equal initialx.

  2. Let y equal initialy.

  3. Let opaque headers be an empty list of cells.

  4. If principal cell is a header cell

    Let in header block be true, and let headers from current header block be a list of cells containing just the principal cell.

    Otherwise

    Let in header block be false and let headers from current header block be an empty list of cells.

  5. Loop: Increment x by Δx; increment y by Δy.

    For each invocation of this algorithm, one of Δx and Δy will be −1, and the other will be 0.

  6. If either x or y is less than 0, then abort this internal algorithm.

  7. If there is no cell covering slot (x, y), or if there is more than one cell covering slot (x, y), return to the substep marked loop.

  8. Let current cell be the cell covering slot (x, y).

  9. If current cell is a header cell
    1. Set in header block to true.

    2. Add current cell to headers from current header block.

    3. Let blocked be false.

    4. If Δx is 0

      If there are any cells in the opaque headers list anchored with the same x-coordinate as the current cell, and with the same width as current cell, then let blocked be true.

      If the current cell is not a column header, then let blocked be true.

      If Δy is 0

      If there is are any cells in the opaque headers list anchored with the same y-coordinate as the current cell, and with the same height as current cell, then let blocked be true.

      If the current cell is not a row header, then let blocked be true.

    5. If blocked is false, then add the current cell to the headers list.

    If current cell is a data cell and in header block is true

    Set in header block to false. Add all the cells in headers from current header block to the opaque headers list, and empty the headers from current header block list.

  10. Return to the step marked loop.

A header cell anchored at the slot with coordinate (x, y) with width width and height height is said to be a column header if any of the following conditions are true:

A header cell anchored at the slot with coordinate (x, y) with width width and height height is said to be a row header if any of the following conditions are true:

A header cell is said to be a column group header if its scope attribute is in the column group state.

A header cell is said to be a row group header if its scope attribute is in the row group state.

A cell is said to be an empty cell if it contains no elements and its text content, if any, consists only of White_Space characters.

4.9.14 Guidance for conformance checkers

This is proposed text and is a very open issue

Conformance checkers must report as a warning or advisory