title: Tables
{@snippet features/build-table-source}
The {@link module:table/table~Table} feature offers table creation and editing tools that help content authors bring tabular data into their documents.
{@snippet features/table}
This feature is enabled by default in all builds. The installation instructions are for developers interested in building their own, custom editor.
To add this feature to your editor, install the @ckeditor/ckeditor5-table package:
npm install --save @ckeditor/ckeditor5-table
Then add Table and TableToolbar plugins to your plugin list and configure the table toolbar:
import Table from '@ckeditor/ckeditor5-table/src/table';
import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';
ClassicEditor
.create( document.querySelector( '#editor' ), {
plugins: [ Table, TableToolbar, Bold, ... ],
toolbar: [ 'insertTable', ... ],
table: {
contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ]
}
} )
.then( ... )
.catch( ... );
The {@link module:table/table~Table} plugin registers the following UI components:
'insertTable' dropdown.'tableColumn' dropdown.'tableRow' dropdown.'mergeTableCells' dropdown.And the following commands:
'insertTable' command implemented by {@link module:table/commands/inserttablecommand~InsertTableCommand}.'insertTableColumnBefore' command implemented by {@link module:table/commands/insertcolumncommand~InsertColumnCommand}.'insertTableColumnAfter' command implemented by {@link module:table/commands/insertcolumncommand~InsertColumnCommand}.'insertTableRowAbove' command implemented by {@link module:table/commands/insertrowcommand~InsertRowCommand}.'insertTableRowBelow' command implemented by {@link module:table/commands/insertrowcommand~InsertRowCommand}.'removeTableColumn' command implemented by {@link module:table/commands/removecolumncommand~RemoveColumnCommand}.'removeTableRow' command implemented by {@link module:table/commands/removerowcommand~RemoveRowCommand}.'setTableColumnHeader' command implemented by {@link module:table/commands/setheadercolumncommand~SetHeaderColumnCommand}.'setTableRowHeader' command implemented by {@link module:table/commands/setheaderrowcommand~SetHeaderRowCommand}.'mergeTableCellRight' command implemented by {@link module:table/commands/mergecellcommand~MergeCellCommand}.'mergeTableCellLeft' command implemented by {@link module:table/commands/mergecellcommand~MergeCellCommand}.'mergeTableCellUp' command implemented by {@link module:table/commands/mergecellcommand~MergeCellCommand}.'mergeTableCellDown' command implemented by {@link module:table/commands/mergecellcommand~MergeCellCommand}.'splitTableCellVertically' command implemented by {@link module:table/commands/splitcellcommand~SplitCellCommand}.'splitTableCellHorizontally' command implemented by {@link module:table/commands/splitcellcommand~SplitCellCommand}.The {@link module:table/tabletoolbar~TableToolbar} plugin introduces two balloon toolbars for tables.
'tableColumn', 'tableRow', and 'mergeTableCells' dropdowns.The table feature allows creating block content (like paragraphs, lists, headings, etc.) in table cells. However, if a table cell contains just one paragraph and this paragraph has no special attributes (like text alignment), this cell contents is considered "inline" and the paragraph is not rendered.
This means that a table cell can be in two states – with an inline content or with a block content. The reason for this differentiation is that most tables contain only inline content (e.g. in the demo above) and it is common for "data tables" to not contain any block content. In such a scenario, printing out <p> elements would be semantically incorrect and also unnecessary. There are, however, scenarios where the user wants to create for example a list inside a table and then the support for block content is necessary too.
When we talk about "rendering" we mean the view layer. In the model, a cell is always filled with at least a `<paragraph>`. The reasons for that are consistency (a cell always has a block content – text is never directly inside `<tableCell>`) and making features like the <kbd>Enter</kbd> support work out of the box (since a `<paragraph>` exists in the model it can be split, despite the fact that it is not present in the view).
The model representation of table cells with an inline content only (a single <paragraph> inside):
<table>
<tableRow>
<tableCell>
<paragraph>Foo</paragraph>
</tableCell>
<tableCell>
<paragraph>Bar</paragraph>
</tableCell>
</tableRow>
</table>
The above model structure will be rendered to the {@link module:editor-classic/classiceditor~ClassicEditor#getData data} as:
<figure class="table">
<table>
<tbody>
<tr>
<td>Foo</td>
<td>Bar</td>
</tr>
</tbody>
</table>
</figure>
In the editing view (the editable container in which the user edits the content) additional <span> elements are create to compensate for the hidden <paragraph> elements:
<figure class="table">
<table>
<tbody>
<tr>
<td><span>Foo</span></td>
<td><span>Bar</span></td>
</tr>
</tbody>
</table>
</figure>
If a table cell contains anything else than a single <paragraph> with no attributes, all those block elements will be rendered.
Example table with a block content (model representation):
<table>
<tableRow>
<tableCell>
<paragraph>Foo</paragraph>
<paragraph>Bar</paragraph>
</tableCell>
<tableCell>
<heading1>Some title</heading1>
</tableCell>
<tableCell>
<paragraph textAlign="right">Baz</paragraph>
</tableCell>
</tableRow>
</table>
The above model structure will be rendered to the data and to the editing view as:
<figure class="table">
<table>
<tbody>
<tr>
<td>
<p>Foo</p>
<p>Bar</p>
</td>
<td>
<h2>Some title</h2>
</td>
<td>
<p style="text-align: right;">Baz</p>
</td>
</tr>
</tbody>
</table>
</figure>
At the moment it is not possible to completely disallow block content in tables. See the [discussing on GitHub](https://github.com/ckeditor/ckeditor5-table/issues/101) about adding a configuration option that would enable that. 👍 if you need this feature.
The source code of the feature is available on GitHub in https://github.com/ckeditor/ckeditor5-table.