Table¶
Placeable in Canvas
A responsive data table that stacks into labelled rows on narrow viewports.
Loading…
Setup required before this component works
Drupal Canvas's built-in text format strips every table tag. Its
allowlist is <strong> <em> <u> <a href> <p> <br> <ul> <ol> <li> — no
<table>, <tr> or <td>. Paste a table into Body without the setup
in the Reference tab below and it renders as run-together text:
Team rosterNameRoleJane DoeEngineer
Canvas locks that format against editing, so this cannot be fixed from the Canvas UI.
Props¶
| Prop | Required | Type | Description | Example |
|---|---|---|---|---|
body |
Optional | string | The table content. | <table class="table tablesaw" data-tablesaw-mode="stack"><caption class="visually-hidden">Team roster</caption><thead><tr><th scope="col">Name</th><th scope="col">Role</th></tr></thead><tbody><tr><td>Jane Doe</td><td>Engineer</td></tr><tr><td>John Smith</td><td>Designer</td></tr></tbody></table> |
color_scheme |
Optional | enum | Dark puts this on a dark background with light text. Defaults to light. |
light, dark |
Give every table a header row: scope on its cells and Tablesaw's stacked view on phones both depend on it. → Full accessibility guidelines
Setup¶
Recommended — Canvas Full HTML. canvas_full_html swaps
Canvas's restricted formats for an unfiltered one, and unlike Canvas's own
formats it is an ordinary editable text format.
composer require drupal/canvas_full_html
drush en canvas_full_html
Then, in this order:
- Turn it on at
/admin/config/content/canvas-full-html— it ships off. - Add a table button. The module's toolbar has no
insertTableby default: go to/admin/config/content/formats/manage/canvas_full_htmland drag Table into the toolbar. Add Source too if authors need it. - Enable Apply IXM table markup in that same format's filter list. This is
what adds
scopeattributes and the Tablesaw classes (see below). Without it, tables render but are not screen-reader labelled and will not stack on mobile. drush cr, then create a new Table component — existing instances stay pinned to the component version they were saved with.
Note the format is granted to the administrator role on install. Give
use text format canvas_full_html to any other role that authors tables.
Alternative — widen a format yourself. If you would rather not add a contrib dependency, create a text format that
permits table markup, enable Apply IXM table markup on it, and point the
Table component's body prop at it with
hook_canvas_storable_prop_shape_alter(). The allowlist needs at least:
<table class data-tablesaw-mode> <thead> <tbody> <tfoot> <tr>
<th scope rowspan colspan> <td rowspan colspan> <caption class>
Do not edit filter.format.canvas_html_block to achieve this. Canvas owns
that config and forbids modification, so the change is a per-site override that
will drift, and it would put a table button on every rich-text prop in the site.
Authoring a table¶
Once set up, drop the Table component onto the page and open Body. The toolbar's table button inserts a grid; click any cell to type in it.
With a table selected, a toolbar appears above it:
| Control | What it does |
|---|---|
| Column | Insert a column left/right, delete a column, or make the first column a header |
| Row | Insert a row above/below, delete a row, or make the first row a header |
| Merge cells | Merge the selection, or split a merged cell |
| Toggle caption | Add a caption above the table |
To delete the whole table, select it by its top-left handle and press Backspace, or delete the Table component itself.
Give the table a header row. A new table has no header row until you add one — use Row → Header row (or
Column → Header column). Both mobile stacking and screen-reader labelling
depend on it. Without one the table still renders and scrolls horizontally, but
it will not stack, and Tablesaw is deliberately not engaged (pointing it at a
headerless table makes it log a <thead> is required and abort).
What the markup filter applies¶
With Apply IXM table markup enabled you never type attributes. On render it adds:
scope="col"to header cells in<thead>, andscope="row"to a header cell that leads a body row — this is what lets a screen reader announce which column and row a cell belongs toclass="table"always, plusclass="tablesaw" data-tablesaw-mode="stack"when the table has a header row, so it stacks into labelled rows on narrow viewports
It is idempotent and leaves alone any scope or data-tablesaw-mode the author
set deliberately.
Tokens used by this component
| Token | Default |
|---|---|
--ixm-table-border-color |
var(--theme-color-border, var(--bs-border-color, #dee2e6)) |
--ixm-table-border-width |
0 |
--ixm-table-focus-outline-color |
var(--theme-color-primary, var(--bs-primary, #0d6efd)) |
--ixm-table-header-accent-color |
var(--theme-color-border-strong, var(--theme-color-primary, var(--bs-primary, #0d6efd))) |
--ixm-table-header-accent-width |
1.5px |
--ixm-table-radius |
var(--theme-radius-lg, var(--bs-border-radius-lg, 0.5rem)) |
--ixm-table-row-border-color |
var(--theme-color-border, var(--bs-border-color, #dee2e6)) |
--ixm-table-stripe-color |
transparent |