View source for Extended Table Markup ▦▤▥

{{toc numerate=1}}

The first significant changes to the table syntax ((/Dev/Release/R6.2/ChangeLog/Chronological are already available)) in version **!!(green)6.2.1!!**.

===Introduction===

Introduce a flexible markup for data tables. Any kind of tables allowed by HTML5 can be created using this markup, from the most basic examples (e.g. simple rows of cells) to complex tables with full support for accessibility options.

Backport and adaption of ((https://web.archive.org/web/20180510222856/http://docs.wikkawiki.org/TableMarkup WikkaWiki Table Markup)). Requires evaluation and changes, not all features are reasonable to implement.

===Implementation Notes===
====HTML5 Table Cell Attributes====

HTML5 table cells, defined by the ##<td>## element, support several attributes for controlling layout, accessibility, and relationships with header cells. Many presentational attributes from earlier HTML versions are now **deprecated** in favor of CSS. 

=====Core Supported Attributes=====

These attributes are valid in HTML5 and should be used for modern web development:

  * **##colspan##**: Specifies how many columns a cell should span.
    - Example: ##<td colspan="2">## makes the cell span two columns.
  * **##rowspan##**: Specifies how many rows a cell should span.
    - Example: ##<td rowspan="3">## makes the cell span three rows.
  * **##headers##**: Associates a data cell with one or more header cells (##<th>##) by referencing their ##id## values. This improves accessibility for screen readers.
    - Example: ##<td headers="header1 header2">##.

=====Deprecated Attributes (Use CSS Instead)=====

The following attributes are obsolete in HTML5. Their functionality should be achieved using CSS:

  - ##align## → ##text-align## or ##margin##
  - ##valign## → ##vertical-align##
  - ##bgcolor## → ##background-color##
  - ##width## → ##width##
  - ##height## → ##height##
  - ##nowrap## → ##white-space: nowrap##
=====Global Attributes=====

The ##<td>## element also supports all ((https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes global HTML attributes)), such as ##class##, ##id##, ##style##, ##data-*##, and ##aria-*## attributes for styling, scripting, and enhanced accessibility.


====Considerations====
  1. use WackoWiki parameter pattern used by actions and formatters
    * ##(x=1 y=name)##
  1. ##^## conflicts with ##""^^superscript^^""## or ##""^C""## in cell content
    * The table cell separator is of utmost importance and should never conflict with other wiki markups.
    * I like the use of the **caret** ##^## (CIRCUMFLEX ACCENT) here, maybe there is a simple workaround to mitigate the conflict with other syntax.
      * ##(?<!\^)\^(?!\^)## ensures the ##^## is not preceded or followed by another ##^##, matches only isolated ##^## characters
  1. use of full parameter names
    * e.g. ##id=tbl1_header## or ##rowspan=2##
  1. support only indirect inline CSS (see Wrappers around formatters)
    * add parameter ##width=## and support ##px## as well as ##%##
    * ##align=## parameter issues and CSS shortcomings with dynamic tables
      * ##td:nth-child(2) { text-align: center; }## is delightful for static tables
    * mainly a sanitization and validation issue
    * %% <td class="[ ' class ' ][ ' bgcolor ' ][ ' align ' ]" style="width: [ ' width ' ];"> %%
  1. current regex supports quotes like ##align="left"## or ##class="style-1 style-2"##
  1. to keep it modest, omit some attributes 
    * ##title##
    * ##height##
    * ##headers##
    * for full HTML support use ##""<# HTML here #>""##
  1. add attributes also to table and caption
    * use ##table_attr()## function to avoid spaghetti code
      * table: align, bgcolor, class, id, width
      * col: bgcolor, class, id, span, width
      * caption:  align, bgcolor, class, id, side
      * cell: align, bgcolor, class, colspan, id, rowspan, scope, width, valign
    * table: ##""#|(align=right)""##
      * float (same as ##wrapper-## CSS classes), class, id
    * caption: ##""?|(side=bottom) Caption |?""##
      * id, side (caption-side: top | bottom)
    * col: ##""!|(width=20%) |(width=20%) |(width=40% bgcolor=green) |(width=20% span=2) |!""##
      * id, class, span, width, align, valign, bgcolor
  1. additional attributes are thinkable for ##font-size##, ##nowrap## and others all translating in adding an additional CSS class to ##syle="style1 sytyle2 ..."##
  2. add different table styles, default is ##usertable## or ##dtable##, replace table syle via ##""#|(type=mytable)""##
  3. add a popup for to WikiEdit to create a table with the provided column and rows, as well header and other options
  1. catch logical errors and mitigate them
    * there can be only one caption and only at the top of the table
  1. error sources
    * mistakenly using the wrong attribute name, ##row## instead of ##col##
    * writing the attribute name wrong, leaving out a letter or messing up letters when writing
    * data cells in the wrong column (e.g. broken legacy tables) due to missing cell spans

====Rational====
The parser breaks down the pipe syntax by row and then each cell. The row and cell syntax delimiter ##|## determines each element and process it recursively.

row 1
→ cell 1 → content
→ cell 2 → content
row 2
→ cell 1 → content
→ cell 2 → content

To avoid syntax conflicts, the delimiter ##|## is always on the inside.
%%
#|
?| Fruit production in 2026 |?
*| | Apples | Pears |*
^| Mary | 300Kg | 320Kg ||
^| John | 400Kg | 630Kg ||
|#
%%

====Syntax====
#|
*| Character | Name | Alias names | Unicode | Wikipedia |*
|| ##""|""## | **Pipe** | vertical bar, vertical line | U+007C | wikipedia:Vertical_bar ||
|| ##""^""## | **Caret** | circumflex accent | U+005E | wikipedia:Caret ||
|#

#|(class=sticky)
|| ^ Syntax ^ Notes ||
^| Start | ##""#|""## | Besides beginning the table, this is also where the table's class is defined – for example, ##class="usertable"##. A table's "class" applies standard WackWiki formatting to that table.
##""#|(class="defaultcenter sticky" align=center)""## ||
^| Caption | ##""?|  |?""## | Required for accessibility purposes on data tables, and placed only between the table start and the first table row.  
##""?| Caption |?""##||
^| Col | ##""!|  |!""## | The ##<col>## HTML element defines one or more columns in a column group represented by its parent ##<colgroup>## element.  
##""!| |(bgcolor=yellow width=300px span=2)  |!""##||
^| Thead   | ##""*|  |*""## | head columns, entire row
##""*| Header 1 | Header 2 |*""## ||
^| Header cell | ##""^|""## | Optional. Each header cell starts with a new line and a ##""^|""##, or several header cells can be placed consecutively on the same line, separated by a single caret ##""^""##. 
##""^| Header | Cell ||""##
##""|| Cell ^ Header ||""## ||
^| Row | ##""||""## | To begin and end a new row of cells, use a double vertical bar ##""||""##.  
##""|| Cell 1 | Cell 2 ||""## ||
^| Cell | ##""|""## | To add a new cell in a row, start each new cell with a single vertical bar ##""|""##, several cells can be placed consecutively on the same line or a new line, separated by single vertical bar ##""|""##. ||
^| Attribute | ##""(attribute=value)""## | cell attributes
##""||(colspan=2 rowspan=2) 2x2 | 1x1 ||""##  ||
^| End | ##""|#""## | To end the table. ||
|#

The table cells as well as the caption are fully editable via wiki syntax.

=====Attributes=====
#|(class="defaultcenter col1left sticky")
!| |(bgcolor=red)  |(bgcolor=red) col |(bgcolor=red) caption |(bgcolor=red span=2) cell |  |!
||(rowspan=2) ^(rowspan=2) table ^(rowspan=2) col ^(rowspan=2) caption ^(colspan=2) cell ^(rowspan=2)  ||
*| th ^ td |*
^| align |(bgcolor=green) +   | –   |(bgcolor=green) +  |(bgcolor=green) +  |(bgcolor=green) +   |  ||
^| bgcolor |(bgcolor=green) + |(bgcolor=green) + |(bgcolor=green) +   |(bgcolor=green) +  |(bgcolor=green) +  |   ||
^| class |(bgcolor=green) + |(bgcolor=green) + |(bgcolor=green) +  |(bgcolor=green) +  |(bgcolor=green) +  |   ||
^| colspan | –   | –   | –   |(bgcolor=green) +  |(bgcolor=green) +  |   ||
^| id |(bgcolor=green) +  |(bgcolor=green) +  |(bgcolor=green) +  |(bgcolor=green) +  |(bgcolor=green) +  |   ||
^| rowspan | –  | –   | –   |(bgcolor=green) +   |(bgcolor=green) +  |   ||
^| scope | –   | –   | –   |(bgcolor=green) +  | –  |   ||
^| side | –   | –   |(bgcolor=green) +   | –   | –  |   ||
^| span | –   |(bgcolor=green) +   | –   | –   | –  |   ||
^| type |(bgcolor=green) +   |  –  | –   | –   | –  |   ||
^| width |(bgcolor=green) + |(bgcolor=green) +   | –   |(bgcolor=green) +  |(bgcolor=green) +  |   ||
^| valign | –  | –  | –  |(bgcolor=green) +  |(bgcolor=green) +  |   ||
|#

#|(class=sticky)
*| # | Attribute | Values | Notes |*
|| 1 ^ ##align## | ##center, left, right, justify## | Specifies the horizontal alignment of the data cell or places the table on the center, left or right side, allowing text and inline elements to wrap around it.
##(align=right)##

To align the data cells in an entire column or table, assign the appropriate CSS selectors using the ##class## attribute. ||
|| 2 ^ ##bgcolor##   | ##blue, red, green, x11colors## | Defines the background color of the data cell. The value is an HTML color; a color keyword.
##(bgcolor=green)## ||
|| 3 ^ ##class## | ##class_name## | available CSS selectors
  * table
    * ##alternate## alternating row shading
    * ##sticky## for sticky header
    * ##""default[left|center|right|top|middle|bottom]""##
    * ##""colN[left|center|right|top|middle|bottom]""## N stands for the column number
    * ##""col-N[left|center|right|top|middle|bottom]""## Align the cells in column N counting from the right.
##""#|(class="defaultcenter col1left col4right")""##  ||
|| 4 ^ ##colspan## | ##number## | Contains a non-negative integer value that indicates how many columns the data cell spans or extends.
##""||(colspan=2) 2x1 | 1x1 ||""##  ||
|| 5 ^ ##id## | ##id_name## | Defines a unique identifier (ID) which must be unique in the whole document.  
##(id=tbl1_summary)## ||
|| 6 ^ ##rowspan## | ##number## | Contains a non-negative integer value that indicates for how many rows the data cell spans or extends.
##""||(rowspan=2) 1x2 | 1x1 ||""##  ||
|| 7 ^ ##scope## | ##row, col, rowgroup, colgroup## | Optional. Defines the cells that the header (defined in the ##<th>##) element relates to. Possible enumerated values are:
  * ##row##: the header relates to all cells of the row it belongs to;
  * ##col##: the header relates to all cells of the column it belongs to;
  * ##rowgroup##: the header belongs to a rowgroup and relates to all of its cells;
  * ##colgroup##: the header belongs to a colgroup and relates to all of its cells.
##""^|(scope=row)""##  ||
|| 8 ^ ##side## | ##top, bottom## | Specifies on which side of the table the caption should be displayed. 
##""?|(side=bottom) Table Caption |?""## ||
|| 9 ^ ##span## | ##number## | Specifies the number of consecutive columns the ##<col>## element spans. 
##""!|(span=1) |(span=2) |!""## ||
|| 10 ^ ##type## | ##class_name## | Use a different table style, default is ##usertable## or ##dtable##.
##""#|(type=mytable)""## ||
|| 11 ^ ##valign## | ##top, middle, bottom## | Specifies the vertical alignment of the data cell. 
##(valign=middle)##||
|| 12 ^ ##width## | ##""number[px|%|em|rem]""## | Defines a recommended data cell width. 
##(width=50%)## ||
|#

  * thead / tfoot / tbody
  * colgroup / col
  * CSS: color, styles, width
    * via predefined classes
  * Global Attributes: id, class, --title--, lang, data-*

=====Colors=====
  1. background colors
    * table header
    * row highlighting
    * subtle background colors
    * web-safe color


#|
||(bgcolor=green) green |(bgcolor=blue) blue ||
||(bgcolor=yellow) yellow |(bgcolor=red) red ||
|#

=====Linebreaks=====
=====Spaces=====
##""|| cell ||""##
##""||(pattern) cell ||""##

#|(class=sticky)
*|(width=30%) Pattern | Output |(width=30%) Note |*
|| ##""()""## |() | ||
|| ##""(hello)""## |(hello) | ||
|| ##""(pattern=value)""## |(pattern=value) | matches valid cell attribute pattern ||
|| ##""(pattern = value)""## |(pattern = value) | matches valid cell attribute pattern ||
|| ##""text""## |text | ||
|| ##""␣text""## | text | ignores heading space ||
|| ##""␣␣text""## |  text | text indention (##<div class="indent"></div>##) ||
|| ##""␣␣␣␣text""## |    text | text indention ||
|| ##""(align=right) text""## |(align=right) text | ||
|| ##""(align=justify) text""## |(align=justify) HTML preserves all whitespace in the source code as text nodes in the DOM, but CSS applies a default whitespace processing algorithm that collapses multiple spaces, tabs, and line breaks into a single space. | ||
|#

======Table Space Ignored======

**HTML and CSS whitespace handling** explains why browsers ignore leading spaces in table cells. HTML preserves all whitespace in the source code as text nodes in the DOM, but **CSS applies a default whitespace processing algorithm** that collapses multiple spaces, tabs, and line breaks into a single space. This behavior is consistent across all inline content, including table cells.

When you have leading spaces in a ##<td>## element, such as ##<td>   Hello</td>##, the browser processes the whitespace as follows:
  ***Leading and trailing whitespace** (spaces, tabs, line breaks) before and after text is ignored in rendering.
  ***Consecutive whitespace characters** (spaces, tabs, line feeds) are collapsed into a single space.
  *Only the **first space** between words is preserved; extra spaces are discarded.

This is not a bug—it's by design. The goal is to ensure readable text formatting without requiring developers to worry about code indentation affecting the displayed layout. For example, the following HTML:
%%(hl html)
<td>   Hello World!</td>
%%
is rendered as:
%%
Hello World!
%%
with only a single space between "Hello" and "World!".

======Solutions to preserve spacing======
If you need to display multiple spaces (e.g., for monospaced text or formatting), use one of these methods:
  * **Use ##white-space: pre##** in CSS to preserve all whitespace:
  %%(hl css)
  td {
    white-space: pre;
  }
  %%
  * **Use non-breaking spaces (##"" ""##)** to force visible spacing:
  %%(hl html)
  <td>  Hello</td>
  %%
  * **Wrap text in a ##<pre>## tag** if you want to preserve all formatting exactly as written.

This behavior applies uniformly across modern browsers and is part of the standard HTML and CSS specification.

====Issues====
  1. **CSS specificity** prevents ##bgcolor## in ##<th>## cells
    * ##.usertable th { background-color: #eee; }##
    * highlight color for hovering above a table row
  1. Currently, there is no way to apply a style to a table row using wiki syntax.
  1. It is not possible to align the text of an entire column via the ##<col>## element but possible via CSS selectors for the ##<table>## element, you must use ##style=“text-align: center;”## or ##td:nth-child(4)## for a specific column; otherwise, the user must apply the style to each individual cell (and who wanna do this?).
    * table ##""#|(class="defaultcenter col4right")""##
      * ##.col4right td:nth-child(4) {text-align: right;}##
      * ##.defaultcenter {text-align: center;}##
    * CSS selectors
      * ##default[left|center|right|top|middle|bottom]##
      * ##colN[left|center|right|top|middle|bottom]## N stands for the column number
  1. As soon as you start defining multiple attributes cell by cell using wiki syntax in a large table with many columns and rows, it quickly becomes counterproductive, especially if you do this over and over again. 
    * possible solutions:
      * inline HTML
      * content templates
      * keep it simple
  1. Should it use the same attribute name ##align## for the table alignment and the cell text alignment?
    * ##.table-[center|left|right]##
    * ##.text-[center|left|right|justify]##

====JavaScript features====
  * sortable tables
    * https://github.com/tristen/tablesort
  * table search
  * column highlighting
====Backwards Compatibility====
The old colspan behaviour is **not compatible** with the new ##colspan## or ##rowspan## attributes, it would add a ##colspan## where it not belongs.

It once expanded omitted cells at the end of a table row for the last cell to fit the previous rows columns.

By removing this behaviour, existing col spans will default to their original colspan which is ##1##. Just add the new ##colspan=Number## attribute to the cell to restore the intended colspan.

%%(php)
<?php
// removed legacy colspan behaviour
if (   ($i == $count)
	&& ($this->cols <> 0)
	&& ($count < $this->cols))
{
	$colspan = ' colspan="' . ($this->cols - $count + 1) . '"';
}
%%

====Sanitization & Validation====
  * Discards attributes not on a whitelist for the given element.
====Documentation====

  1. update Table section in ((/Doc/English/Formatting Text Formatting page))
  1. add ((!/TableMarkupGuide Table Markup Guide)) (draft)


====Resources====
  * https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Structuring_content/HTML_table_basics
  * https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/table
  * https://html.spec.whatwg.org/multipage/tables.html#the-table-element
  * https://alistapart.com/article/web-typography-tables/
  * https://css-tricks.com/complete-guide-table-element/

===Examples===
%%
#| 
|| ^ Heading 1 ^ Heading 2 ||
^| Heading 3    | Row 1 Col 2          | Row 1 Col 3 ||
^| Heading 4    | no colspan | ||
^| Heading 5    | Row 3 Col 2          | Row 3 Col 3 ||
|#
%%

#| 
|| ^ Heading 1 ^ Heading 2 ||
^| Heading 3    | Row 1 Col 2          | Row 1 Col 3 ||
^| Heading 4    | no colspan | ||
^| Heading 5    | Row 3 Col 2          | Row 3 Col 3 ||
|#

%%
#|
?| Fruit production in the last **two** years |?
*| |(colspan=2) Apples |(colspan=2) Pears |*
*| | 2025 | 2026 | 2025 | 2026 |*
^| Mary | 300Kg | 320Kg | 400kg | 280Kg ||
^| John | 400Kg | 630Kg | 210Kg | 300Kg ||
|#
%%

#|
?| Fruit production in the last **two** years |?
*| |(colspan=2) Apples |(colspan=2) Pears |*
*| | 2025 | 2026 | 2025 | 2026 |*
^| Mary | 300Kg | 320Kg | 400kg | 280Kg ||
^| John | 400Kg | 630Kg | 210Kg | 300Kg ||
|#

%%
#|
||(align=left width=50%) left |(rowspan=3 valign=top) top |(rowspan=3 valign=middle) middle |(rowspan=3 valign=bottom) bottom ||
||(align=center) center ||
||(align=right) right ||
|#
%%

#|
||(align=left width=50%) left |(rowspan=3 valign=top) top |(rowspan=3 valign=middle) middle |(rowspan=3 valign=bottom) bottom ||
||(align=center) center ||
||(align=right) right ||
|#

%%
#|
||(rowspan=2) 2 lines | line 1 ||
|| line 2 ||
||(colspan=2) line 3, 2 columns broad ||
|#
%%

#|
||(rowspan=2) 2 lines | line 1 ||
|| line 2 ||
||(colspan=2) line 3, 2 columns broad ||
|#


%%
#|
^|(colspan=2 rowspan=2) 2x2 |(colspan=2) 2x1 |(rowspan=2) 1x2 ||
||(rowspan=2) 1x2 | 1x1 ||
|| 1x1 | 1x1 |(colspan=2) 2x1 ||
|#
%%

#|
^|(colspan=2 rowspan=2) 2x2 |(colspan=2) 2x1 |(rowspan=2) 1x2 ||
||(rowspan=2) 1x2 | 1x1 ||
|| 1x1 | 1x1 |(colspan=2) 2x1 ||
|#


#|
^| 1 | 1 ||
^| 2 | 2 | 4 ||
^| 3 | 3 | 6 | 9 ||
^| 4 | 4 | 8 | 12 | 16 ||
^| 5 | 5 | 10 | 15 | 20 | 25 ||
^| 6 | 6 | 12 | 18 | 24 | 30 | 36 ||
^| 7 | 7 | 14 | 21 | 28 | 35 | 42 | 49 ||
^| 8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 ||
^| 9 | 9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 ||
*| × | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |*
|#

===Feedback===
Please provide feedback.