Table Borders

The borders on a table are controlled using the frame and grid block attributes. You can combine these two attributes to achieve a variety of border styles for your tables.

Frame

The border around a table is controlled using the frame attribute on the table. The frame attribute defaults to the value all (implied value), which draws a border on each side of the table. This default can be changed by setting the table-frame document attribute. You can override the default value by setting the frame attribute on the table to the value all, ends, sides or none.

The ends value draws a border on the top and bottom of the table.

Example 1. Table with frame=ends
[frame=ends]
|===
|Column 1, header row |Column 2, header row |Column 3, header row

|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2

|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Result of Example 1
Column 1, header row Column 2, header row Column 3, header row

Cell in column 1, row 2

Cell in column 2, row 2

Cell in column 3, row 2

Cell in column 1, row 3

Cell in column 2, row 3

Cell in column 3, row 3

The sides value draws a border on the right and left side of the table.

Example 2. Table with frame=sides
[frame=sides]
|===
|Column 1, header row |Column 2, header row |Column 3, header row

|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2

|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Result of Example 2
Column 1, header row Column 2, header row Column 3, header row

Cell in column 1, row 2

Cell in column 2, row 2

Cell in column 3, row 2

Cell in column 1, row 3

Cell in column 2, row 3

Cell in column 3, row 3

The none value removes the borders around the table.

Example 3. Table with frame=none
[frame=none]
|===
|Column 1, header row |Column 2, header row |Column 3, header row

|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2

|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Result of Example 3
Column 1, header row Column 2, header row Column 3, header row

Cell in column 1, row 2

Cell in column 2, row 2

Cell in column 3, row 2

Cell in column 1, row 3

Cell in column 2, row 3

Cell in column 3, row 3

Grid

The borders between the cells in a table are controlled using the grid attribute on the table. The grid attribute defaults to the value all (implied value), which draws a border between all cells. This default can be changed by setting the table-grid document attribute. You can override the default value by setting the grid attribute on the table to the value all, rows, cols or none.

The rows value draws a border between the rows of the table.

Example 4. Table with grid=rows
[grid=rows]
|===
|Column 1, header row |Column 2, header row |Column 3, header row

|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2

|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Result of Example 4
Column 1, header row Column 2, header row Column 3, header row

Cell in column 1, row 2

Cell in column 2, row 2

Cell in column 3, row 2

Cell in column 1, row 3

Cell in column 2, row 3

Cell in column 3, row 3

The cols value draws borders between the columns.

Example 5. Table with grid=cols
[grid=cols]
|===
|Column 1, header row |Column 2, header row |Column 3, header row

|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2

|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Result of Example 5
Column 1, header row Column 2, header row Column 3, header row

Cell in column 1, row 2

Cell in column 2, row 2

Cell in column 3, row 2

Cell in column 1, row 3

Cell in column 2, row 3

Cell in column 3, row 3

The none value removes all borders between the cells.

Example 6. Table with grid=none
[grid=none]
|===
|Column 1, header row |Column 2, header row |Column 3, header row

|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2

|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Result of Example 6
Column 1, header row Column 2, header row Column 3, header row

Cell in column 1, row 2

Cell in column 2, row 2

Cell in column 3, row 2

Cell in column 1, row 3

Cell in column 2, row 3

Cell in column 3, row 3

Interaction with row and column spans

Using row and column spans may interfere with the placement of borders on a table. This is a limitation of styling HTML using CSS.

When a cell extends into other rows or columns, that cell is not represented in the HTML for the rows or columns it extends into. This is a problem if the cell reaches the boundary of the table. The CSS selector only matches the cell where it starts and thus does not detect when it is touching the table boundary. It therefore cannot add or remove the border as it would for a 1x1 cell (i.e., a cell confined to a single row and column).

The interference with border placement caused by row and column spans does not always happen. Borders on a table with a rowspan or colspan that reaches the table boundary will always work correctly when the frame and grid are congruent. In this context, congruent means the frame and grid are contributing borders to the same edges.

Here are those scenarios in which the frame and grid are congruent:

  • frame=all, grid=all

  • frame=all, grid=none

  • frame=all, grid=rows

  • frame=all, grid=cols

  • frame=ends, grid=rows

  • frame=sides, grid=cols

  • frame=none, grid=none

If you use row and column spans in a table, you are strongly encouraged to use one of these frame and grid combinations.