25. XHTML Tables Module

Contents

This section is informative. For the normative version, see [XHTML2].

The Tables Module provides elements for marking up tabular information in a document.

The module supports the following elements, attributes, and content model:

Elements Attributes Minimal Content Model
table Common caption?, summary?, ( col* | colgroup* ), (( thead?, tfoot?, tbody+ ) | ( tr+ ))
summary Common (PCDATA | Flow)*
col Common, @span (Number) EMPTY
colgroup Common, @span (Number) col*
thead Common tr+
tfoot Common tr+
tbody Common tr+
tr Common, Forms ( td | th)+
td Common, @abbr (Text), @axis (CDATA), @colspan (Number), @headers (IDREFS), @rowspan (Number), @scope ("row", "col", "rowgroup", "colgroup") (PCDATA | Flow)*
th Common, @abbr (Text), @axis (CDATA), @colspan (Number), @headers (IDREFS), @rowspan (Number), @scope ("row", "col", "rowgroup", "colgroup") (PCDATA | Flow)*

When this module is used, it adds the table element to the Structural content set of the Structural Module.

Implementations: RELAX NG, XML Schema

25.1. The col and colgroup elements

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation
span = Number
This attribute must be an integer > 0; the default value is 1. This specifies the number of columns in a colgroup, or specifies the number of columns "spanned" by the col element.

Values mean the following:

  • In the absence of a @span attribute, each colgroup defines a column group containing one column.
  • If the @span attribute is used with the colgroup element and the value is set to N > 0, that defines a column group containing N columns.
  • If the @span attribute is used with the col element and the value is set to N > 1, the current col element shares its attributes with the next N-1 columns.

User agents must ignore this attribute if the colgroup element contains one or more col elements. Instead, the value must be computed by summing the span attributes of the enclosed col elements.

The colgroup element allows authors to create structural divisions within a table. Authors may highlight this structure through style sheets. For example, the author may wish to divide the columns into logical groups such as the student's permanent address, phone number and emergency contact information. And group the student's local address, phone and email address into another logical group.

A table may either contain a single implicit column group (no colgroup element delimits the columns) or any number of explicit column groups (each delimited by an instance of the colgroup element).

The col element allows authors to share attributes among several columns without implying any structural grouping. The "span" of the col element is the number of columns that will share the element's attributes. For example, the author may wish to apply a specific style to the student's permanent data and apply a different style to the student's local data.

The colgroup element creates an explicit column group. The number of columns in the column group may be specified in two, mutually exclusive ways:

  1. The colgroup @span attribute (default value 1) specifies the number of columns in the group.
  2. Each embedded col element in the colgroup represents one or more columns in the group.

The advantage of using the colgroup element is that authors may logically group multiple columns. By grouping columns, the author can apply rules across the entire group. The author can also apply column width balancing across the group of columns. For example, if the author has a table with five columns and the author divides the table into two column groups, one with three columns and the other with two columns. The author could define the first column group to consume 300 pixels and the second column group to consume 100 pixels. Each column within the first column group would be 100 pixels wide and the remaining two columns would be 50 pixels wide. If the author added embedded col elements, she could force one or more columns to be a specific width and the remaining columns within the group would be evenly divided within the remaining allotted width.

For example, the following table defines a column group and embedded columns with differing widths.

Example

<style type="text/css">
#colgrp1 { width: 300px }
#col1 { width: 100px }
#col2 { width: 50px }
</style>
...
<table>
  <colgroup id="colgrp1">
    <col id="col1" span="3"/>
    <col id="col2" span="2"/>
  </colgroup>
<em>...the rest of the table...</em>
</table>

In this example, the defined width for the colgroup constrains all of the columns to fit within that value regardless of the of the defined values within the col elements. In this example, the width of the columns within the column group must be constrained to fit the defined width of the column group.

When it is necessary to single out a column (e.g., for style information, to specify width information, etc.) within a group, authors must identify that column with a col element.

The col element allows authors to group together attribute specifications for table columns. The col does not group columns together structurally -- that is the role of the colgroup element. col elements are empty and serve only as a support for attributes. They may appear inside or outside an explicit column group (i.e., colgroup element).

25.1.1. Calculating the number of columns in a table

There are two ways to determine the number of columns in a table (in order of precedence):

  1. If the table element contains any colgroup or col elements, user agents should calculate the number of columns by summing the following:
  2. Otherwise, if the table element contains no colgroup or col elements, user agents should base the number of columns on what is required by the rows. The number of columns is equal to the number of columns required by the row with the most columns, including cells that span multiple columns. For any row that has fewer than this number of columns, the end of that row should be padded with empty cells. The "end" of a row depends on the directionality of a table.

It is an error if a table contains colgroup or col elements and the two calculations do not result in the same number of columns.

Once the user agent has calculated the number of columns in the table, it may group them into a colgroup.

25.2. The summary element

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation

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

User agents MUST provide access to the content of the summary element. As an example, access could be provided through a menu option, a mouse-over function, or through a dialog.

The following example demonstrates the difference between a table caption and a table summary.

Example

<table>
  <caption>Student Class Roster</caption>
  <summary>The table defines the class roster.
    The columns contain the following data:
    students name, permanent address, permanent phone,
    local address, local phone,
    declared major, assigned academic advisor,
    student standing</summary>
  <em>...the rest of the table...</em>
</table>

25.3. The table element

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation

The table element contains all other elements that specify the caption, column groups, columns, rows, and content for a table.

25.3.1. Visual Rendering

All style associated with table rendering MUST use proper CSS2 properties.

Although CSS2 is not required, the equivalent effect MUST BE followed and integrated into the rendering model.

The following informative list describes what operations visual user agents may carry out when rendering a table:

25.3.2. Table directionality

The directionality of a table is either the inherited directionality (the default is left-to-right) or that specified by the @dir attribute for the table element.

For a left-to-right table, column zero is on the left side and row zero is at the top. For a right-to-left table, column zero is on the right side and row zero is at the top.

When a user agent allots extra cells to a row, extra row cells are added to the right of the table for left-to-right tables and to the left side for right-to-left tables.

Note that table is the only element on which @dir reverses the visual order of the columns; a single table row ( tr) or a group of columns ( colgroup) cannot be independently reversed.

When set for or inherited by the table element, the @dir attribute also affects the direction of text within table cells (since the @dir attribute is inherited by block-level elements).

To specify a right-to-left table, set the @dir attribute as follows:

Example

<table dir="rtl">
<em>...the rest of the table...</em>
</table>

The direction of text in individual cells can be changed by setting the @dir attribute in an element that defines the cell.

25.3.3. Table rendering by non-visual user agents

This section provides more detailed discussion on cell header data and how non-visual agents may utilize that information.

25.3.3.1. Associating header information with data cells

Non-visual user agents such as speech synthesizers and Braille-based devices may use the following td and th element attributes to render table cells more intuitively:

In the following example, we assign header information to cells by setting the @headers attribute. Each cell in the same column refers to the same header cell (via the @id attribute).

Example

<table>
<caption>Cups of coffee consumed by each senator</caption>
<summary>This table charts the number of cups
          of coffee consumed by each senator, the type
          of coffee (decaf or regular), and whether
          taken with sugar.</summary>
<tbody>
   <tr>
      <th id="t1">Name</th>
      <th id="t2">Cups</th>
      <th id="t3" abbr="Type">Type of Coffee</th>
      <th id="t4">Sugar?</th>
   </tr>
   <tr>
      <td headers="t1">T. Sexton</td>
      <td headers="t2">10</td>
      <td headers="t3">Espresso</td>
      <td headers="t4">No</td>
   </tr>
   <tr>
      <td headers="t1">J. Dinnen</td>
      <td headers="t2">5</td>
      <td headers="t3">Decaf</td>
      <td headers="t4">Yes</td>
   </tr>
</tbody>
</table>

A speech synthesizer might render this table as follows:

Example

Caption: Cups of coffee consumed by each senator
Summary: This table charts the number of cups
         of coffee consumed by each senator, the type
         of coffee (decaf or regular), and whether
         taken with sugar.
Name: T. Sexton,   Cups: 10,   Type: Espresso,   Sugar: No
Name: J. Dinnen,   Cups: 5,    Type: Decaf,      Sugar: Yes

Note how the header "Type of Coffee" is abbreviated to "Type" using the @abbr attribute.

Here is the same example substituting the @scope attribute for the @headers attribute. Note the value "col" for the @scope attribute, meaning "all cells in the current column":

Example

<table>
<caption>Cups of coffee consumed by each senator</caption>
<summary>
  This table charts the number of cups
  of coffee consumed by each senator, the type
  of coffee (decaf or regular), and whether
  taken with sugar.
</summary>
<tbody>
   <tr>
      <th scope="col">Name</th>
      <th scope="col">Cups</th>
      <th scope="col" abbr="Type">Type of Coffee</th>
      <th scope="col">Sugar?</th>
   </tr>
   <tr>
      <td>T. Sexton</td>
      <td>10</td>
      <td>Espresso</td>
      <td>No</td>
   </tr>
   <tr>
      <td>J. Dinnen</td>
      <td>5</td>
      <td>Decaf</td>
      <td>Yes</td>
   </tr>
</tbody>
</table>

Here's a somewhat more complex example illustrating other values for the @scope attribute:

Example

<table>
<summary>
  History courses offered in the community of
  Bath arranged by course name, tutor, summary,
  code, and fee
</summary>
<thead>
  <tr>
    <th colspan="5" scope="colgroup">Community Courses -- Bath Autumn 1997</th>
  </tr>
</thead>
<tbody>
  <tr>
    <th scope="col" abbr="Name">Course Name</th>
    <th scope="col" abbr="Tutor">Course Tutor</th>
    <th scope="col">Summary</th>
    <th scope="col">Code</th>
    <th scope="col">Fee</th>
  </tr>
  <tr>
    <td scope="row">After the Civil War</td>
    <td>Dr. John Wroughton</td>
    <td>
       The course will examine the turbulent years in England
       after 1646. <em>6 weekly meetings starting Monday 13th
       October.</em>
    </td>
    <td>H27</td>
    <td>&amp;pound;32</td>
  </tr>
  <tr>
    <td scope="row">An Introduction to Anglo-Saxon England</td>
    <td>Mark Cottle</td>
    <td>
       One day course introducing the early medieval
       period reconstruction the Anglo-Saxons and
       their society. <em>Saturday 18th October.</em>
    </td>
    <td>H28</td>
    <td>&amp;pound;18</td>
  </tr>
  <tr>
    <td scope="row">The Glory that was Greece</td>
    <td>Valerie Lorenz</td>
    <td>
     Birthplace of democracy, philosophy, heartland of theater, home of
     argument. The Romans may have done it but the Greeks did it
     first. <em>Saturday day school 25th October 1997</em>
    </td>
    <td>H30</td>
    <td>&amp;pound;18</td>
  </tr>
</tbody>
</table>

A graphical user agent might render this as:

A table with merged cells

Note the use of the @scope attribute with the "row" value. Although the first cell in each row contains data, not header information, the @scope attribute makes the data cell behave like a row header cell. This allows speech synthesizers to provide the relevant course name upon request or to state it immediately before each cell's content.

25.3.3.2. Categorizing cells

Users browsing a table with a speech-based user agent may wish to hear an explanation of a cell's contents in addition to the contents themselves. One way the user might provide an explanation is by speaking associated header information before speaking the data cell's contents (see the section on associating header information with data cells).

Users may also want information about more than one cell, in which case header information provided at the cell level (by @headers, @scope, and @abbr) may not provide adequate context. Consider the following table, which classifies expenses for meals, hotels, and transport in two locations (San Jose and Seattle) over several days:

Image of a table listing travel expenses at two locations: San Jose and Seattle, by date, and category (meals, hotels, and transport), shown with subtitles

Users might want to extract information from the table in the form of queries:

Each query involves a computation by the user agent that may involve zero or more cells. In order to determine, for example, the costs of meals on 25 August, the user agent must know which table cells refer to "Meals" (all of them) and which refer to "Dates" (specifically, 25 August), and find the intersection of the two sets.

To accommodate this type of query, the table model allows authors to place cell headers and data into categories. For example, for the travel expense table, an author could group the header cells "San Jose" and "Seattle" into the category "Location", the headers "Meals", "Hotels", and "Transport" in the category "Expenses", and the four days into the category "Date". The previous three questions would then have the following meanings:

Authors categorize a header or data cell by setting the @axis attribute for the cell. For instance, in the travel expense table, the cell containing the information "San Jose" could be placed in the "Location" category as follows:

Example

  <th id="a6" axis="location">San Jose</th>

Any cell containing information related to "San Jose" should refer to this header cell via either the @headers or the @scope attribute. Thus, meal expenses for 25-Aug-1997 should be marked up to refer to @id attribute (whose value here is "a6") of the "San Jose" header cell:

Example

  <td headers="a6">37.74</td>

Each @headers attribute provides a list of @id references. Authors may thus categorize a given cell in any number of ways (or, along any number of "headers", hence the name).

Below we mark up the travel expense table with category information:

Example

<table>
<caption>Travel Expense Report</caption>
<summary>
  This table summarizes travel expenses
  incurred during August trips to
  San Jose and Seattle
</summary>
<tbody>
   <tr>
      <th></th>
      <th id="a2" axis="expenses">Meals</th>
      <th id="a3" axis="expenses">Hotels</th>
      <th id="a4" axis="expenses">Transport</th>
      <td>subtotals</td>
   </tr>
   <tr>
      <th id="a6" axis="location">San Jose</th>
      <th></th>
      <th></th>
      <th></th>
      <td></td>
   </tr>
   <tr>
      <td id="a7" axis="date">25-Aug-97</td>
      <td headers="a6 a7 a2">37.74</td>
      <td headers="a6 a7 a3">112.00</td>
      <td headers="a6 a7 a4">45.00</td>
      <td></td>
   </tr>
   <tr>
      <td id="a8" axis="date">26-Aug-97</td>
      <td headers="a6 a8 a2">27.28</td>
      <td headers="a6 a8 a3">112.00</td>
      <td headers="a6 a8 a4">45.00</td>
      <td></td>
   </tr>
   <tr>
      <td>subtotals</td>
      <td>65.02</td>
      <td>224.00</td>
      <td>90.00</td>
      <td>379.02</td>
   </tr>
   <tr>
      <th id="a10" axis="location">Seattle</th>
      <th></th>
      <th></th>
      <th></th>
      <td></td>
   </tr>
   <tr>
      <td id="a11" axis="date">27-Aug-97</td>
      <td headers="a10 a11 a2">96.25</td>
      <td headers="a10 a11 a3">109.00</td>
      <td headers="a10 a11 a4">36.00</td>
      <td></td>
   </tr>
   <tr>
      <td id="a12" axis="date">28-Aug-97</td>
      <td headers="a10 a12 a2">35.00</td>
      <td headers="a10 a12 a3">109.00</td>
      <td headers="a10 a12 a4">36.00</td>
      <td></td>
   </tr>
   <tr>
      <td>subtotals</td>
      <td>131.25</td>
      <td>218.00</td>
      <td>72.00</td>
      <td>421.25</td>
   </tr>
   <tr>
      <th>Totals</th>
      <td>196.27</td>
      <td>442.00</td>
      <td>162.00</td>
      <td>800.27</td>
   </tr>
</tbody>
</table>

Note that marking up the table this way also allows user agents to avoid confusing the user with unwanted information. For instance, if a speech synthesizer were to speak all of the figures in the "Meals" column of this table in response to the query "What were all my meal expenses?", a user would not be able to distinguish a day's expenses from subtotals or totals. By carefully categorizing cell data, authors allow user agents to make important semantic distinctions when rendering.

Of course, there is no limit to how authors may categorize information in a table. In the travel expense table, for example, we could add the additional categories "subtotals" and "totals".

This specification does not require user agents to handle information provided by the @axis attribute, nor does it make any recommendations about how user agents may present @axis information to users or how users may query the user agent about this information.

However, user agents, particularly speech synthesizers, may want to factor out information common to several cells that are the result of a query. For instance, if the user asks "What did I spend for meals in San Jose?", the user agent would first determine the cells in question (25-Aug-1997: 37.74, 26-Aug-1997:27.28), then render this information. A user agent speaking this information might read it:

Example

   Location: San Jose. Date: 25-Aug-1997. Expenses, Meals: 37.74
   Location: San Jose. Date: 26-Aug-1997. Expenses, Meals: 27.28

or, more compactly:

Example

   San Jose, 25-Aug-1997, Meals: 37.74
   San Jose, 26-Aug-1997, Meals: 27.28

An even more economical rendering would factor the common information and reorder it:

Example

   San Jose, Meals, 25-Aug-1997: 37.74
                    26-Aug-1997: 27.28

User agents that support this type of rendering should allow authors a means to customize rendering (e.g., through style sheets).

25.3.3.3. Algorithm to find heading information

In the absence of header information from either the @scope or @headers attribute, user agents may construct header information according to the following algorithm. The goal of the algorithm is to find an ordered list of headers. (In the following description of the algorithm the table directionality is assumed to be left-to-right.)

25.4. The tbody element

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation

The tbody element contains rows of table data. In tables that also contain thead or tfoot elements, all of these sections must contain the same number of columns.

25.5. The td and th elements

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation
abbr = Text
This attribute should be used to provide an abbreviated form of the cell's content, and may be rendered by user agents when appropriate in place of the cell's content. Abbreviated names should be short since user agents may render them repeatedly. For instance, speech synthesizers may render the abbreviated headers relating to a particular cell before rendering that cell's content.
axis = CDATA
This attribute may be used to place a cell into conceptual categories that can be considered to form axes in an n-dimensional space. User agents may give users access to these categories (e.g., the user may query the user agent for all cells that belong to certain categories, the user agent may present a table in the form of a table of contents, etc.). Please consult the section on categorizing cells for more information. The value of this attribute is a comma-separated list of category names.
colspan = Number
This attribute specifies the number of columns spanned by the current cell. The default value of this attribute is one ("1"). The value zero ("0") means that the cell spans all columns from the current column to the last column of the column group ( colgroup) in which the cell is defined.
headers = IDREFS
This attribute specifies the list of header cells that provide header information for the current data cell. The value of this attribute is a space-separated list of cell names; those cells must be named by setting their @id attribute. Authors generally use the @headers attribute to help non-visual user agents render header information about data cells (e.g., header information is spoken prior to the cell data), but the attribute may also be used in conjunction with style sheets. See also the @scope attribute.
rowspan = Number
This attribute specifies the number of rows spanned by the current cell. The default value of this attribute is one ("1"). The value zero ("0") means that the cell spans all rows from the current row to the last row of the current table section (rowgroup) in which the cell is defined. thead, tbody, and tfoot elements are rowgroups.
scope = row|col|rowgroup|colgroup
This attribute specifies the set of data cells for which the current header cell provides header information. This attribute may be used in place of the @headers attribute, particularly for simple tables. When specified, this attribute must have one of the following values:
  • row: The current cell provides header information for the rest of the row that contains it (see also the section on table directionality).
  • col: The current cell provides header information for the rest of the column that contains it.
  • rowgroup: The header cell provides header information for the rest of the row group that contains it.
  • colgroup: The header cell provides header information for the rest of the column group that contains it.

Table cells may contain two types of information: header information and data. This distinction enables user agents to render header and data cells distinctly, even in the absence of style sheets. For example, visual user agents may present header cell text with a bold font. Speech synthesizers may render header information with a distinct voice inflection.

The th element defines a cell that contains header information. User agents have two pieces of header information available: the contents of the th element and the value of the @abbr attribute. User agents must render either the contents of the cell or the value of the @abbr attribute. For visual media, the latter may be appropriate when there is insufficient space to render the full contents of the cell. For non-visual media @abbr may be used as an abbreviation for table headers when these are rendered along with the contents of the cells to which they apply.

The @headers and @scope attributes also allow authors to help non-visual user agents process header information. Please consult the section on labeling cells for non-visual user agents for information and examples.

The td element defines a cell that contains data.

Cells may be empty (i.e., contain no data).

25.5.1. Cells that span several rows or columns

Cells may span several rows or columns. The number of rows or columns spanned by a cell is set by the @rowspan and @colspan attributes for the th and td elements.

In this table definition, we specify that the cell in row four, column two should span a total of three columns, including the current column.

<table>
<caption>Cups of coffee consumed by each senator</caption>
<tbody>
   <tr>
      <th>Name</th>
      <th>Cups</th>
      <th>Type of Coffee</th>
      <th>Sugar?</th>
   </tr>
   <tr>
      <td>T. Sexton</td>
      <td>10</td>
      <td>Espresso</td>
      <td>No</td>
   </tr>
   <tr>
      <td>J. Dinnen</td>
      <td>5</td>
      <td>Decaf</td>
      <td>Yes</td>
   </tr>
   <tr>
      <td>A. Soria</td>
      <td colspan="3"><em>Not available</em></td>
   </tr>
</tbody>
</table>

This table might be rendered on a tty device by a visual user agent as follows:

Cups of coffee consumed by each senator
 --------------------------------------
 |   Name  |Cups|Type of Coffee|Sugar?|
 --------------------------------------
 |T. Sexton|10  |Espresso      |No    |
 --------------------------------------
 |J. Dinnen|5   |Decaf         |Yes   |
 --------------------------------------
 |A. Soria |Not available             |
 --------------------------------------

The next example illustrates (with the help of table borders) how cell definitions that span more than one row or column affect the definition of later cells. Consider the following table definition:

<table>
<tbody>
   <tr>
      <td>1</td>
      <td rowspan="2">2</td>
      <td>3</td>
   </tr>
   <tr>
      <td>4</td>
      <td>6</td>
   </tr>
   <tr>
      <td>7</td>
      <td>8</td>
      <td>9</td>
      <td></td>
   </tr>
</tbody>
</table>

As cell "2" spans the first and second rows, the definition of the second row will take it into account. Thus, the second td in row two actually defines the row's third cell. Visually, the table might be rendered to a tty device as:

-------------
| 1 | 2 | 3 |
----|   |----
| 4 |   | 6 |
----|---|----
| 7 | 8 | 9 |
-------------

while a graphical user agent might render this as:

Image of a table with rowspan=2

Note that if the td defining cell "6" had been omitted, an extra empty cell would have been added by the user agent to complete the row.

Similarly, in the following table definition:

<table>
<tbody>
   <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
   </tr>
   <tr>
      <td colspan="2">4</td>
      <td>6</td>
   </tr>
   <tr>
      <td>7</td>
      <td>8</td>
      <td>9</td>
   </tr>
</tbody>
</table>

cell "4" spans two columns, so the second td in the row actually defines the third cell ("6"):

-------------
| 1 | 2 | 3 |
--------|----
| 4     | 6 |
--------|----
| 7 | 8 | 9 |
-------------

A graphical user agent might render this as:

Image of a table with colspan=2

Defining overlapping cells is an error. User agents may vary in how they handle this error (e.g., rendering may vary).

The following illegal example illustrates how one might create overlapping cells. In this table, cell "5" spans two rows and cell "7" spans two columns, so there is overlap in the cell between "7" and "9":

<table>
<tbody>
   <tr>
      <td>1</td>
      <td>2</td>
      <td>3</td>
   </tr>
   <tr>
      <td>4</td>
      <td rowspan="2">5</td>
      <td>6</td>
   </tr>
   <tr>
      <td colspan="2">7</td>
      <td>9</td>
   </tr>
</tbody>
</table>

25.6. The thead and tfoot elements

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation

Table rows may be grouped into a table head, table foot, and one or more table body sections, using the thead, tfoot and tbody elements, respectively. This division enables user agents to support scrolling of table bodies independently of the table head and foot. When long tables are printed, the table head and foot information may be repeated on each page that contains table data.

The table head and table foot should contain information about the table's columns. The table body must contain rows of table data.

When present, each thead, tfoot, and tbody creates a row group. Each row group must contain at least one row, defined by the tr element.

If the thead, tfoot, and tbody elements are used, and a rowspan attribute is used within a group, the rowspan must remain within the group boundaries of which it is defined.

This example illustrates the order and structure of the table head, foot, and bodies.

Example

<table>
<thead>
     <tr> <em>...header information...</em></tr>
</thead>
<tfoot>
     <tr> <em>...footer information...</em></tr>
</tfoot>
<tbody>
     <tr> <em>...first row of block one data...</em></tr>
     <tr> <em>...second row of block one data...</em></tr>
</tbody>
<tbody>
     <tr> <em>...first row of block two data...</em></tr>
     <tr> <em>...second row of block two data...</em></tr>
     <tr> <em>...third row of block two data...</em></tr>
</tbody>
</table>

tfoot must appear before tbody within a table definition so that user agents can render the foot before receiving all of the (potentially numerous) rows of data.

25.7. The tr element

Attributes

The Common collection
A collection of other attribute collections, including: Bi-directional, Core, Edit, Embedding, Events, Hypertext, I18N, Map, and Metainformation

The tr elements acts as a container for a row of table cells.

This sample table contains three rows, each begun by the tr element:

<table>
<caption>Cups of coffee consumed by each senator</caption>
<summary>This table charts the number of cups
  of coffee consumed by each senator, the type 
  of coffee (decaf or regular), and whether 
  taken with sugar.</summary>
<tbody>
   <tr> ...A header row...</tr>
   <tr> ...First row of data...</tr>
   <tr> ...Second row of data...</tr>
</tbody>
</table>

25.8. Issues

Why no nested colgroup or rowgroup? PR #7828
State: Feedback
Resolution: None
User: None

Notes:
We have reviewed this request, but don't understand how the additional markup supports the use case. What problem are you trying to solve exactly?

td/th scope attribute - rowgroup == (tbody, thead, tfoot) PR #7879
State: Open
Resolution: None
User: None

Notes:
Agree that we need to tighten up the terminology.

nesting colgroup and rowgroups PR #7881
State: Open
Resolution: None
User: None

Notes:
While there are notional "rowgroups" there are no explicit arbitrary rowgroups in HTML nor in XHTML because rows are explicit in tables. colgroups, on the other hand, exist because HTML / XHTML needs a way of referring to columns. Asked the submitter for more information and an example including a description of what the advantages would be.