23. Tables
Tables are one of the most intricate, yet refined areas of the AsciiDoc syntax. Armed with a bit of knowledge, you should discover that they are both easy to create and easy to read in raw form. Yet, under all that simplicity, they are remarkably sophisticated.
Tables are delimited by |=== and made up of cells.
The default table data format is PSV (Prefix Separated Values), which means that the processor creates a new cell each time it encounters a vertical bar (|).
Cells are grouped into rows.
Each row must share the same number of cells, taking into account any column or row spans.
Then, each consecutive cell in a row is placed in a separate column.
The simple table example below consists of two columns and three rows.
|=== (1)
(2)
| Cell in column 1, row 1 | Cell in column 2, row 1 (3)
(4)
| Cell in column 1, row 2 | Cell in column 2, row 2
| Cell in column 1, row 3 | Cell in column 2, row 3
|=== (1)
| 1 | The table’s content boundaries are defined by a vertical bar followed by three equal signs (|===). |
| 2 | Inserting a blank line before the first row is a trick to ensure the first row is not treated as the table header. |
| 3 | The new cell is marked by a vertical bar (|). |
| 4 | Rows can optionally be separated by any number of blank lines. |
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 1, row 3 |
Cell in column 2, row 3 |
Like with all blocks, you can add a role to a table using the role attribute.
The role attribute becomes a CSS class when converted to HTML.
The preferred shorthand for assigning the role attribute is to put the role name in the first position of the block attribute list prefixed with a . character, as shown here:
[.rolename]
|===
| Cell in column 1, row 1 | Cell in column 2, row 1 | Cell in column 3, row 1
| Cell in column 1, row 2 | Cell in column 2, row 2 | Cell in column 3, row 2
|===
Leading and trailing spaces around cell content is stripped and, therefore, don’t affect the table’s layout when rendered. The two examples below illustrate how leading and trailing spaces don’t change the rendered table’s layout.
|===
|Cell in column 1, row 1|Cell in column 2, row 1
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
|===
| Cell in column 1, row 1 | Cell in column 2, row 1
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
There are multiple ways to group cells into a row. The cells in a row can be placed on:
-
the same line
-
consecutive, individual lines
-
a combination of a and b
|===
|Cell in column 1, row 1 |Cell in column 2, row 1 |Cell in column 3, row 1
|Cell in column 1, row 2 |Cell in column 2, row 2 |Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
When the cells of a row are individually entered on consecutive lines, the cols attribute is needed to specify the number of columns in the table.
If the cols attribute is not set, the first non-blank line inside the block delimiter (|===) determines the number of columns.
[cols="3*"] (1)
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| 1 | The cols attribute states that this table has three columns.
The * is a repeat operator which is explained in the column specifiers section. |
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Rows can be formed from adjacent lines of individual cells and cells listed on the same line.
[cols="3*"]
|===
|Cell in column 1, row 1 |Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2 |Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The next sections describe and demonstrate the variety of ways you can customize table cells, rows and columns.
23.1. Columns
The number of columns in a table is determined by the number of cells found in the first non-blank line after the table delimiter (|===) or by the values assigned to the cols attribute.
For example, the syntax in the two examples below will both converted to a table with two columns.
|===
|Cell in column 1, row 1 |Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
[cols="2*"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
When a single number is assigned to the cols attribute, its value indicates the number of columns. Each column will be the same width. However, the number of columns can also be assigned as a comma delimited list. The number of entries in the list determines the number of columns.
The comma delimited list below creates a table with four columns of equal width.
[cols="1,1,1,1"]
This syntax provides that same result:
[cols="4*"]
Now, let’s talk about that asterisk in the syntax above.
23.2. Column Formatting
The AsciiDoc syntax provides a variety of ways to control the size, style and layout of content within columns. These specifiers can be applied to whole columns.
To apply a specifier to a column, you must set the cols attribute and assign it a value.
A column specifier can contain any of the following components:
-
multiplier
-
align
-
width
-
style
Each component is optional.
The multiplier operator (*) is used when you want a specifier to apply to more than one consecutive column.
If used, the multiplier must always be placed at the beginning of the specifier.
For example:
[cols="3*"] (1)
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| 1 | The table will consist of three columns, as indicated by the 3. The * operator ensures that the default layout and style will be applied to all of the columns. |
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The alignment component allows you to horizontally or vertically align a column’s content.
Content can be horizontally aligned left (<), center (^), or right (>).
To horizontally center the content in all of the columns, add the ^ operator after the multiplier.
[cols="3*^"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
What if you only want to center the content in the last column?
Assign the default styles to the preceding columns, and ^ to the last column in a comma separated list.
[cols="2*,^"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Let’s specify a different horizontal alignment for each column.
[cols="<,^,>"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
You’ll notice that the content in the examples above is only centered on the horizontal.
It can also be aligned vertically when the alignment operator is prefixed with a dot (.).
Content can be vertically aligned to the top (<), middle (^), or bottom (>) of a cell.
To vertically align the content to the middle of the cells in all of the columns, add a . and then the ^ operator after the multiplier.
[cols="3*.^"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
If you only want to align the content to the bottom of each cell in the last column, you’d assign the default styles to the preceding columns, and > to the last column in a comma separated list.
[cols="2*,.>"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Let’s specify a different vertical alignment for each column.
[cols=".<,.^,.>"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Finally, we’ll also horizontally center the content in the last column.
[cols=".<,.^,^.>"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
When both a horizontal and vertical alignment is assigned to a column, the horizontal alignment operator must precede the vertical operator.
The width component sets the width of a column. Its value can be a proportional integer (the default is 1) or a percentage (1 to 99).
[cols="1,2,6"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
When assigning percentage values to the cols attribute, you do not need to include the percent sign (%).
[cols="50,20,30"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Let’s create a table with custom widths and alignments.
[cols=".<2,.^5,^.>3"]
|===
|Cell in column 1, row 1 with lots and lots and lots and lots of content
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2 and another bucket of content, and then a jelly roll of content
|===
Cell in column 1, row 1 with lots and lots and lots and lots of content |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 and another bucket of content, and then a jelly roll of content |
The style component must always be located at the end of the specifier. When no style name is provided column contents will be processed as regular inline text.
The column styles are described in the table below.
| Style Name | Value | Description |
|---|---|---|
AsciiDoc |
|
Supports block-level elements (paragraphs, delimited blocks, and block macros). This style effectively creates a nested, standalone AsciiDoc document. Implicit attributes such as doctitle from the parent document will be shadowed. Custom attributes are inherited. |
Emphasis |
|
Text is italicized |
Header |
|
Header styles are applied to the column |
Literal |
|
Column content is treated as if it were inside a literal block |
Monospaced |
|
Text is rendered in monospaced font |
None (default style) |
|
Text is handled like a normal paragraph. Supports all markup (i.e., inline formatting, inline macros) that is permitted in a paragraph. |
Strong |
|
Text is bolded |
Verse |
|
Column content is treated as if it were inside a verse block |
Let’s apply the header style to the first column, the monospaced style to the second, the strong style to the third, and the emphasis style to the fourth.
[cols="h,m,s,e"]
|===
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 4, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|Cell in column 4, row 2
|===
Cell in column 1, row 1 |
|
Cell in column 3, row 1 |
Cell in column 4, row 1 |
|---|---|---|---|
Cell in column 1, row 2 |
|
Cell in column 3, row 2 |
Cell in column 4, row 2 |
Specifiers can also be applied to individual cells.
23.3. Cell Formatting
In addition to sharing many of the column specifier capabilities, cell specifiers allow cells to span rows and columns. Like a column specifier, a cell specifier is made up of components. These components, listed and defined below, are all optional.
-
span
-
align
-
style
A cell specifier is prefixed directly to the cell delimiter (|) preceding the content you want to customize.
The span component can duplicate a cell or have it span multiple rows or columns.
To duplicate a cell in multiple, consecutive columns, prefix the | with the multiplication factor and the * operator.
|===
|Cell in column 1, row 1 |Cell in column 2, row 1 |Cell in column 3, row 1
3*|Same cell content in columns 1, 2, and 3
|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Same cell content in columns 1, 2, and 3 |
Same cell content in columns 1, 2, and 3 |
Same cell content in columns 1, 2, and 3 |
Cell in column 1, row 3 |
Cell in column 2, row 3 |
Cell in column 3, row 3 |
To have a cell span multiple, consecutive columns, prefix the | with the span factor and the + operator.
|===
|Cell in column 1, row 1 |Cell in column 2, row 1 |Cell in column 3, row 1
3+|Content in a single cell that spans columns 1, 2, and 3
|Cell in column 1, row 3
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Content in a single cell that spans columns 1, 2, and 3 |
||
Cell in column 1, row 3 |
Cell in column 2, row 3 |
Cell in column 3, row 3 |
If you want to have a cell span multiple, consecutive rows, prefix the span factor with a dot (.).
|===
|Cell in column 1, row 1 |Cell in column 2, row 1 |Cell in column 3, row 1
.2+|Content in a single cell that spans rows 2 and 3
|Cell in column 2, row 2
|Cell in column 3, row 2
|Cell in column 2, row 3
|Cell in column 3, row 3
|===
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Content in a single cell that spans rows 2 and 3 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Cell in column 2, row 3 |
Cell in column 3, row 3 |
Of course you can combine spanning over columns and rows.
The number before the dot (.) is the number of columns to span and the number after the dot (.) is the number of rows to span.
|===
|Column 1, row 1 |Column 2, row 1 |Column 3, row 1 |Column 4, row 1
|Column 1, row 2
2.3+|Content in a single cell that spans over rows and columns
|Column 4, row 2
|Column 1, row 3
|Column 4, row 3
|Column 1, row 4
|Column 4, row 4
|===
Column 1, row 1 |
Column 2, row 1 |
Column 3, row 1 |
Column 4, row 1 |
Column 1, row 2 |
Content in a single cell that spans over rows and columns |
Column 4, row 2 |
|
Column 1, row 3 |
Column 4, row 3 |
||
Column 1, row 4 |
Column 4, row 4 |
||
The alignment component for cells works the same as the column specifier alignment component.
[cols="3"]
|===
^|Prefix the `{vbar}` with `{caret}` to center content horizontally
<|Prefix the `{vbar}` with `<` to align the content to the left horizontally
>|Prefix the `{vbar}` with `>` to align the content to the right horizontally
.^|Prefix the `{vbar}` with a `.` and `{caret}` to center the content in the cell vertically
.<|Prefix the `{vbar}` with a `.` and `<` to align the content to the top of the cell
.>|Prefix the `{vbar}` with a `.` and `>` to align the content to the bottom of the cell
3+^.^|This content spans three columns (`3{plus}`) and is centered horizontally (`{caret}`) and vertically (`.{caret}`) within the cell.
|===
Prefix the |
Prefix the |
Prefix the |
Prefix the |
Prefix the |
Prefix the |
This content spans three columns ( |
||
To use a pipe (|) within the content of a cell without creating a new cell, you must use the {vbar} attribute.
|
The style component can also be applied to individual cells.
For example, you can apply the AsciiDoc element styles to an individual cell by prefixing the vertical bar with an a.
[cols="2"]
|===
a|This cell is prefixed with an `a`, so the processor interprets the following lines as an AsciiDoc list.
* List item 1
* List item 2
* List item 3
|This cell *is not* prefixed with an `a`, so the processor does not interpret the following lines as an AsciiDoc list.
* List item 1
* List item 2
* List item 3
a|This cell is prefixed with an `a`, so the processor honors the `lead` style on the following paragraph.
[.lead]
I am a paragraph styled with the lead attribute.
|This cell *is not* prefixed with an `a`, so the processor does not honor the `lead` style on the following paragraph.
[.lead]
I am a paragraph styled with the lead attribute.
|===
This cell is prefixed with an
|
This cell is not prefixed with an * List item 1 * List item 2 * List item 3 |
This cell is prefixed with an I am a paragraph styled with the lead attribute. |
This cell is not prefixed with an [.lead] I am a paragraph styled with the lead attribute. |
Source code listing can be placed inside cells by using the listing syntax.
|===
|Source Code 1 |Source Code 2
a|
[source,python]
----
import os
print "%s" %(os.uname())
----
a|
[source,python]
----
import os
print ("%s" %(os.uname()))
----
|===
| Source Code 1 | Source Code 2 |
|---|---|
|
|
For the grand finale, let’s apply a variety of specifiers to individual cells.
|===
2*>m|This content is duplicated across two columns.
It is aligned right horizontally.
And it is monospaced.
.3+^.>s|This cell spans 3 rows. The content is centered horizontally, aligned to the bottom of the cell, and strong.
e|This content is emphasized.
.^l|This content is aligned to the top of the cell and literal.
v|This cell contains a verse
that may one day expound on the
wonders of tables in an
epic sonnet.
|===
|
|
This cell spans 3 rows. The content is centered horizontally, aligned to the bottom of the cell, and strong. |
This content is emphasized. |
This content is aligned to the top of the cell and literal. |
|
This cell contains a verse that may one day expound on the wonders of tables in an epic sonnet. |
23.4. Header Row
The first row of a table is promoted to a header row if the header option is set (either explicitly or implicitly).
You can enable the header option by adding the header keyword to the comma-separated list of values in the options attribute on the table.
You can also enable the header option by adding the %header directive to the table style (the first positional attribute).
In the example below, the table has an attribute list containing an options attribute that includes the header option.
[cols=2*,options="header"]
|===
|Name of Column 1
|Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
| Name of Column 1 | Name of Column 2 |
|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Alternately, you can define the header row based on how you layout the table. Asciidoctor use the following conventions to determine when the first row should become the header row:
-
The first line of content inside the table block delimiters is not empty.
-
The second line of content inside the table block delimiters is empty.
-
The
optionsattribute has not been specified in the block attributes (prior to 1.5.5).
As seen in the result of the example below, if all of these rules hold, then the first row of the table is treated as a header.
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
| Name of Column 1 | Name of Column 2 |
|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
If you want to suppress this implicit behavior of promoting the first row to a header row, set the option value noheader (or add the %noheader directive to the table style).
Notice that when the implicit method of assigning the header row is used, it’s not necessary to set the cols attribute.
That’s because the number of columns are determined by the number of cells in the first line if the cols attribute is absent.
| We’re considering using a similar convention for enabling the footer in the future. Thus, if you rely on this convention to enable the header row, it’s advised that you not put all the cells in the last row on the same line unless you intend on making it the footer row. |
23.5. Footer Row
The last row of a table can be styled as a footer by adding the footer keyword to the options attribute.
[options="footer"]
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Footer in column 1, row 3
|Footer in column 2, row 3
|===
| Name of Column 1 | Name of Column 2 |
|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Footer in column 1, row 3 |
Footer in column 2, row 3 |
23.6. Table Width
By default, a table will span the width of the content area.
To constrain the width of the table to a fixed value, set the width attribute in the table’s attribute list.
The width is an integer percentage value ranging from 1 to 100.
The % sign is optional.
[width=75%]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
Alternately, you can make the width fit the content by setting the autowidth option.
The columns inherit this setting, so individual columns will also be sized according to the content.
[%autowidth]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
If you want each column to have an automatic width, but want the table to span the width of the content area, add the stretch role to the table or set the width attribute to 100%.
[%autowidth.stretch]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The autowidth option is not recognized by the DocBook converter.
|
If you want to apply autowidth only to certain columns, use the special value ~ as the width of the column.
In this case, width values are assumed to be a percentage value (i.e., 100-based).
[cols="25h,~,~"]
|===
|small |as big as the column needs to be |the rest
|===
23.7. Table Borders
The borders on a table are controlled using the frame and grid attributes.
You can combine these two attributes to achieve a variety of border styles for your tables.
23.7.1. Frame
The border around a table is controlled using the frame attribute.
By default, the frame attribute is assigned the all value, which draws a border on each side of the table.
If you set the frame attribute, you can override the default value with the values topbot, sides or none.
The topbot value draws a border on the top and bottom of the table.
[frame=topbot]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The sides value draws a border on the right and left side of the table.
[frame=sides]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The none value removes the borders around the table.
[frame=none]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
23.7.2. Grid
The borders between the cells in a table are controlled using the grid attribute.
By default, the grid attribute is assigned the all value, which draws a border between all cells.
If you set the grid attribute, you can override the default value with the values rows, cols or none.
The rows value draws a border between the rows of the table.
[grid=rows]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The cols value draws borders between the columns.
[grid=cols]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
The none value removes all borders between the cells.
[grid=none]
|===
|Name of Column 1 |Name of Column 2 |Name of Column 3
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 3, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|Cell in column 3, row 2
|===
| Name of Column 1 | Name of Column 2 | Name of Column 3 |
|---|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 3, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Cell in column 3, row 2 |
23.8. Striping
Starting with Asciidoctor 2.0, the rows in the body of a table are not shaded.
You can configure the rows to be striped (as in zebra stripes) using an attribute.
Use the stripes table attribute to configure the stripes for a single table.
Use the table-stripes document attribute to configure stripes for all tables.
Striping is done by adding a background color to the specified rows. The stripes attribute accepts the following values:
-
none - no rows are shaded (default in Asciidoctor >= 2.0)
-
even - even rows are shaded (default in Asciidoctor < 2.0)
-
odd - odd rows are shaded
-
all - all rows are shaded
-
hover - the row under the mouse cursor is shaded (HTML only)
In the following example, the stripes are enabled for even rows in the table body (the row that contains A2, B2, and C2).
[cols=3*, stripes=even]
|===
| A1
| B1
| C1
| A2
| B2
| C2
| A3
| B3
| C3
|===
Under the covers, the stripes attribute applies the CSS class stripes-<value> (e.g., stripes-none) to the table tag.
As a shorthand, you can simply apply the CSS class to the table directly using a role.
[.stripes-even,cols=3*]
|===
| A1
| B1
| C1
| A2
| B2
| C2
| A3
| B3
| C3
|===
If you want to apply stripes to all tables in the document, set the table-stripes attribute in the document header.
You can still override this setting per table.
:table-stripes: even
[cols=3*]
|===
| A1
| B1
| C1
| A2
| B2
| C2
| A3
| B3
| C3
|===
In the HTML output, table striping is done using CSS and thus depends on the stylesheet to supply the necessary styles. The default stylesheet for Asciidoctor includes these styles.
23.9. Orientation
A table can be displayed in landscape (rotated 90 degrees counterclockwise) using the rotate option (preferred):
[%rotate]
|===
|a |b
|c |d
|===
or the orientation attribute:
[orientation=landscape]
|===
|a |b
|c |d
|===
Currently, this is only implemented by the DocBook backend (it sets the attribute orient="land").
23.10. Nested Tables
Table cells marked with the AsciiDoc table style (a) support nested tables in addition to normal block content.
To distinguish the inner table from the enclosing one, you need to use !=== as the table delimiter and a cell separator that differs from that used for the enclosing table.
The default cell separator for a nested table is !, though you can choose another character by defining the separator attribute on the table.
| Although nested tables are not technically valid in DocBook 5.0, the DocBook toolchain processes them anyway. |
The following example contains a nested table in the last cell. Notice the nested table has its own format, independent of that of the outer table:
[cols="1,2a"]
|===
| Col 1 | Col 2
| Cell 1.1
| Cell 1.2
| Cell 2.1
| Cell 2.2
[cols="2,1"]
!===
! Col1 ! Col2
! C11
! C12
!===
|===
| Col 1 | Col 2 | ||||
|---|---|---|---|---|---|
Cell 1.1 |
Cell 1.2 |
||||
Cell 2.1 |
Cell 2.2
|
We recommend using nested tables sparingly. There’s usually a better way to present the information.
23.11. Table Caption
If you specify a title on a table, the title will be used as part of the table’s caption. Adding a title also designates the table as a formal table.
By default, the title of a formal table is prefixed with the label Table <n>. followed by a space, where <n> is the 1-based index of all formal tables in the document.
.A formal table
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
| Name of Column 1 | Name of Column 2 |
|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
You can customize the caption label by specifying the caption attribute.
(Don’t let the name of the attribute mislead you.
The caption attribute only sets the caption’s label, not the whole caption line).
| If you want a space between the label and the title, you must add a trailing space to the value of the caption attribute. |
[caption="Table A. "]
.A formal table
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
| Name of Column 1 | Name of Column 2 |
|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
If you want the caption of the table to only consist of the caption label, use the following syntax:
[caption=,title='{table-caption} {counter:table-number}']
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
Alternately, you can write is as follows:
.{blank}
[caption='{table-caption} {counter:table-number}']
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
If you want to exclude the caption label altogether, simply assign a blank value to the caption attribute.
[caption=]
.A formal table
|===
|Name of Column 1 |Name of Column 2
|Cell in column 1, row 1
|Cell in column 2, row 1
|Cell in column 1, row 2
|Cell in column 2, row 2
|===
| Name of Column 1 | Name of Column 2 |
|---|---|
Cell in column 1, row 1 |
Cell in column 2, row 1 |
Cell in column 1, row 2 |
Cell in column 2, row 2 |
Alternatively, you can disable the caption label for tables globally by undefining the table-caption document attribute.
:table-caption!:
23.12. Escaping the Cell Separator
The parser scans for the cell separator to partition cells before it processes the cell text. So even if you try to hide the cell separator using an inline passthrough, the parser will see it. If the cell contain contains the cell separator, you must escape that character. There are three ways to escape it:
-
Prefix the character with a leading backslash (i.e.,
\|), which will be removed from the output. -
Use the
{vbar}attribute reference as a substitute. -
Change the cell separator used by the table.
Unless you do one of these things, the cell separator will be interpreted as a cell boundary.
Consider the following example, which escapes the cell separator using a leading backslash:
[cols=2*]
|====
|The default separator in PSV tables is the \| character.
|The \| character is often referred to as a "`pipe`".
|====
This table will render as follows:
The default separator in PSV tables is the | character. |
The | character is often referred to as a “pipe”. |
Notice that the pipe character appears without the leading backslash (i.e., unescaped) in the rendered result.
An alternative is to use the {vbar} attribute reference as a substitute.
This approach produces the same result as the previous example.
[cols=2*]
|====
|The default separator in PSV tables is the {vbar} character.
|The {vbar} character is often referred to as a "`pipe`".
|====
Escaping each cell separator character that appears in the content of a cell can be tedious. There are also times when you can’t or don’t want to modify the cell content (perhaps because it is being included from another file). To address these cases, AsciiDoc allows you to override the cell separator.
The cell separator is controlled using the separator attribute on the table block.
You’ll want to select a character that will never be used for content.
A good candidate is the broken bar, or ¦.
Here’s the previous example rewritten using a custom separator.
[cols=2*,separator=¦]
|====
¦The default separator in PSV tables is the | character.
¦The | character is often referred to as a "`pipe`".
|====
Notice that it’s no longer necessary to escape the pipe character in the content of the table cells. You can safely use the original cell separator in the cell content and not worry about it being interpreted as the boundary of a cell.
23.13. Delimiter-Separated Values
Tables can also be populated from data formatted as delimiter-separated values (i.e., data tables).
In contrast with the PSV format, in which the delimiter is placed in front of each cell value, the delimiter in a delimiter-separated format (CSV, TSV, DSV) is placed between the cell values (called a separator) and does not accept a cell formatting spec.
Each line of data is assumed to represent a single row, though you’ll learn that’s not a strict rule.
How the table data gets interpreted is controlled by the format and separator attributes on the table.
Let’s consider an example of using comma-separated values (CSV) to populate an AsciiDoc table with data.
To instruct the processor to read the data as CSV, set the value of the format attribute on the table to csv.
When the format attribute is set to csv, the default data separator is a comma (,), as seen in the table below.
[%header,format=csv]
|===
Artist,Track,Genre
Baauer,Harlem Shake,Hip Hop
The Lumineers,Ho Hey,Folk Rock
|===
| Artist | Track | Genre |
|---|---|---|
Baauer |
Harlem Shake |
Hip Hop |
The Lumineers |
Ho Hey |
Folk Rock |
This feature is particularly useful when you want to populate a table in your manuscript from data stored in a separate file. You can do so using the include directive between the table delimiters, as shown here:
[%header,format=csv]
|===
include::tracks.csv[]
|===
If your data is separated by tabs instead of commas, set the format to tsv (tab-separated values) instead.
Now let’s consider an example of using delimited data (DSV) to populate an AsciiDoc table with data.
To instruct the processor to read the data as DSV, set the value of the format attribute on the table to dsv.
When the format attribute is set to dsv, the default data separator is a colon (:), as seen in the table below.
[%header,format=dsv]
|===
Artist:Track:Genre
Robyn:Indestructable:Dance
The Piano Guys:Code Name Vivaldi:Classical
|===
| Artist | Track | Genre |
|---|---|---|
Robyn |
Indestructable |
Dance |
The Piano Guys |
Code Name Vivaldi |
Classical |
23.13.1. Data Table Formats
The CSV and TSV data formats are parsed differently from the DSV data format. The following two sections outline those differences.
CSV and TSV
Table data in either CSV or TSV format is parsed according to the following rules, loosely based on RFC 4180:
-
The default delimiter for CSV is a comma (
,) while the default delimiter for TSV is a tab character. -
Blank lines are skipped (unless enclosed in a quoted value).
-
Whitespace surrounding each value is stripped.
-
Values can be enclosed in double quotes (
").-
A quoted value may contain zero or more separator or newline characters.
-
A newline begins a new row unless the newline is enclosed in double quotes.
-
A quoted value may include the double quote character if escaped using another double quote (
""). -
Newlines in quoted values are retained (as of 1.5.7).
-
-
If rows do not have the same number of cells (“ragged” tables), cells are shuffled to fully fill the rows.
-
This is different behavior than Excel, which pads short rows with empty cells.
-
Extra cells at the end of the last row get dropped.
-
As a rule of thumb, data for a single row should be on the same line.
-
DSV
Table data in DSV format is parsed according to the following rules:
-
The default delimiter for DSV is a colon (
:). -
Blank lines are skipped.
-
Whitespace surrounding each value is stripped.
-
The delimiter character can be included in the value if escaped using a single backslash (
\:). -
If rows do not have the same number of cells (“ragged” tables), cells are shuffled to fully fill the rows.
23.13.2. Custom Delimiters
Each data format has a default separator associated with it (csv = comma, tsv = tab, dsv = colon), but the separator can be changed to any character (or even a string of characters) by setting the separator attribute on the table.
Here’s an example of a DSV table that uses a custom separator character (i.e., delimiter):
[format=dsv,separator=;]
|===
a;b;c
d;e;f
|===
To make a TSV table, you can set the format attribute to csv and the separator to \t.
Though the tsv format is preferred.
|
The separator is independent of the processing rules for the format.
If you set format=dsv and separator=,, the data will be processed using the DSV rules, even though the data looks like CSV.
23.13.3. Shorthand Notation for Data Tables
Asciidoctor provides shorthand notation for specifying the data format of a table.
The first position of the table block delimiter (i.e., |===) can be replaced by a built-in delimiter to set the table format (e.g., ,=== for CSV).
To make a CSV table, you can use ,=== as the table block delimiter:
,===
Artist,Track,Genre
Baauer,Harlem Shake,Hip Hop
,===
| Artist | Track | Genre |
|---|---|---|
Baauer |
Harlem Shake |
Hip Hop |
To make a DSV table, you can use :=== as the table block delimiter:
:===
Artist:Track:Genre
Robyn:Indestructable:Dance
:===
| Artist | Track | Genre |
|---|---|---|
Robyn |
Indestructable |
Dance |
When using either the CSV or DSV shorthand, you do not need to set the format attribute as it’s implied.
To make a TSV table, you can set the format attribute to tsv instead of having to set the format to csv and the separator to \t.
In this case, you can use either |=== or ,=== as the table block delimiter.
There is no special delimited block notation for a TSV table.
23.13.4. Formatting Cells in a Data Table
The delimited formats do not provide a way to express formatting of individual table cells.
Instead, you can apply cell formatting to all cells in a given column using the cols spec on the table:
[format=csv,cols="1h,1a"]
|===
Sky,image::sky.jpg[]
Forest,image::forest.jpg[]
|===
Data tables do not support cells that span multiple rows or columns, since that information can only be expressed at the cell level. You are advised to use the PSV format if you need that functionality.
23.14. Summary
| Attribute | Description | Value | Description | Notes |
|---|---|---|---|---|
|
comma-separated list of column specifiers |
specifiers |
see Columns for details |
|
|
data format of the table’s contents |
|
cells are delimited by |
|
|
cells are delimited by a colon ( |
|||
|
cells are delimited by a comma ( |
|||
|
cells are delimited by a tab character (aka tab-separated values) |
|||
|
character used to separate cells |
|
default for top-level tables |
|
|
default for nested tables |
|||
user-defined |
any sequence of literal characters (e.g., |
|||
|
draws a border around the table |
|
border on all sides (default) |
|
|
border on top and bottom |
|||
|
no borders |
|||
|
border on left and right sides |
|||
|
draws boundary lines between rows and columns |
|
draws boundary lines around each cell (default) |
|
|
draws boundary lines between columns |
|||
|
draws boundary lines between rows |
|||
|
no boundary lines |
|||
|
controls row shading (via background color) |
|
no rows are shaded |
|
|
even rows are shaded (default in Asciidoctor < 2.0) |
|||
|
odd rows are shaded |
|||
|
row under the mouse cursor is shaded (HTML only) |
|||
|
all rows are shaded |
|||
|
horizontally aligns table within page width |
|
aligns to left side of page (default) |
Not yet implemented in Asciidoctor.
Applies to HTML output only.
The |
|
aligns to right side of page |
|||
|
horizontally aligns to center of page |
|||
|
floats the table to the specified side of the page |
|
floats the table to the left side of the page (default) |
Applies to HTML output only.
Must be used in conjunction with the table’s |
|
floats the table to the right side of the page |
|||
|
horizontally aligns all of the cell contents in a table |
|
aligns the contents of the cells to the left (default) |
Not implemented in Asciidoctor.
Define instead using column or cell specifiers (e.g., |
|
aligns the contents of the cells to the right |
|||
|
aligns the contents to the cell centers |
|||
|
vertically aligns all of the cell contents in a table |
|
aligns the cell contents to the top of the cell (default) |
Define instead using column or cell specifiers (e.g., |
|
aligns the cell contents to the bottom of the cell |
|||
|
aligns the cell contents to the middle of the cell |
|||
|
rotates the table |
|
rotated 90 degrees counterclockwise |
Equivalent to setting the rotate option, which is preferred. DocBook only. |
|
comma separated list of option names |
|
promotes first row to the table header |
header and footer rows are omitted by default |
|
promotes last row to the table footer |
|||
|
allows the table to split across a page (default) |
Mutually exclusive. DocBook only (specifically for generating PDF output). |
||
|
prevents the table from being split across a page |
|||
|
disables explicit column widths (ignores |
|||
|
Prints the table in landscape |
Equivalent to setting the orientation to landscape. DocBook only. |
||
|
the table width relative to the available page width |
user defined value |
a percentage value between 0% and 100% |