Data Table

A Table people work with: sort it, select rows, act on a row, page through it, and see where it stands while it loads or when there's nothing to show. Specification: docs/components/data-table.md

Basics

A <div class="canon-data-table"> around a Table and a Pagination. Headers with aria-sort sort; the data-column="select" column selects rows (Shift+click selects a range); the data-column="actions" column holds each row's actions, here a Menu. With data-local all rows are in the page, and canon.js sorts them and shows them a page at a time.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com$436.68Waiting
Mrs. Jo Emardjovany66@hotmail.com$984.24Delivered
Lauren Monahanjermaine.corkery@gmail.com$916.69In delivery
Antoinette Wilkinsonmarcos.zulauf@gmail.com$378.25Cancelled
Glen Tremblayora_gutmann@gmail.com$357.93Ready
Marjorie Mertzjoshua_hodkiewicz@yahoo.com$954.96In delivery
Janet Hyattgraham.cassin@yahoo.com$569.18Delivered
Dwayne Kubalva.kemmer@gmail.com$1,204.50Waiting
Rosa Larkinverna_hand@hotmail.com$88.40Delivered

Bulk actions

A <div class="canon-data-table-bulk" role="region"> in the data table, named, holding the actions for the selected rows: Buttons by meaning (the main action, data-intent="danger" for a destructive one), a menu button for more. While rows are selected it floats at the bottom of the window, with Clear selection and the count (screen readers hear it change); the app's buttons read the selection from canon-select. Select every row on this page: it offers to select all 12 (here the rows are in the page, so canon.js checks them; for the app's rows, canon-select says allMatching). Without canon.js the bar stays under the table, for a form round trip.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com$436.68Waiting
Mrs. Jo Emardjovany66@hotmail.com$984.24Delivered
Lauren Monahanjermaine.corkery@gmail.com$916.69In delivery
Antoinette Wilkinsonmarcos.zulauf@gmail.com$378.25Cancelled
Glen Tremblayora_gutmann@gmail.com$357.93Ready
Marjorie Mertzjoshua_hodkiewicz@yahoo.com$954.96In delivery
Janet Hyattgraham.cassin@yahoo.com$569.18Delivered
Dwayne Kubalva.kemmer@gmail.com$1,204.50Waiting
Rosa Larkinverna_hand@hotmail.com$88.40Delivered

Search, filters, columns, export

A .canon-data-table-toolbar before the table holds a search field (type="search"), a data-panel="filters" button and a data-panel="columns" button; data-align="end" sends an item to the far end. Headers say what their column holds (data-type: text, number, date, choice), which makes them filterable. Filters show as chips under the toolbar: a chip opens its filter, its × removes it; a filtered column also shows a filter button in its header that opens its filter. Columns shows, hides, orders (drag the grip, or its arrow keys) and pins them. An Export item with data-export="csv" downloads the matching rows.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com$436.68Waiting
Mrs. Jo Emardjovany66@hotmail.com$984.24Delivered
Lauren Monahanjermaine.corkery@gmail.com$916.69In delivery
Antoinette Wilkinsonmarcos.zulauf@gmail.com$378.25Cancelled
Glen Tremblayora_gutmann@gmail.com$357.93Ready
Marjorie Mertzjoshua_hodkiewicz@yahoo.com$954.96In delivery
Janet Hyattgraham.cassin@yahoo.com$569.18Delivered
Dwayne Kubalva.kemmer@gmail.com$1,204.50Waiting
Rosa Larkinverna_hand@hotmail.com$88.40Delivered

Long tables: a header that stays, text that's cut

Give the frame a max-block-size and it scrolls down too, with the header staying at the top. data-wrap="truncate" on a header cuts its column's text with "…"; the full text shows on hover and is read in full by screen readers.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com$436.68Waiting
Mrs. Jo Emardjovany66@hotmail.com$984.24Delivered
Lauren Monahanjermaine.corkery@gmail.com$916.69In delivery
Antoinette Wilkinsonmarcos.zulauf@gmail.com$378.25Cancelled
Glen Tremblayora_gutmann@gmail.com$357.93Ready
Marjorie Mertzjoshua_hodkiewicz@yahoo.com$954.96In delivery
Janet Hyattgraham.cassin@yahoo.com$569.18Delivered
Dwayne Kubalva.kemmer@gmail.com$1,204.50Waiting
Rosa Larkinverna_hand@hotmail.com$88.40Delivered

Cut in the middle: file names, paths and ids

data-wrap="middle" cuts a column's text in its middle and keeps its end: its last third, at least 8 characters, and a file name's extension with the 5 characters before it. Use it where values share a start and differ at the end (file names, paths, hashes). The full text shows on hover and is read in full by screen readers.

Files
NameOwnerSizeModified
Q3-board-report-finance-review-v12-final.pdfAmara Okafor2.4 MB
Q3-board-report-finance-review-v11.pdfAmara Okafor2.3 MB
customer-export-emea-2026-09-28T14-02-11Z.csvJonas Weber18.7 MB
customer-export-emea-2026-09-21T14-02-07Z.csvJonas Weber18.1 MB
onboarding-checklist-warehouse-staff.docxLi Na96 KB

Row actions as buttons

A few actions can sit in the row as buttons: a Toolbar named for its row, so each row is one Tab stop and the arrow keys move between its buttons. The actions column needs no header text.

Orders
OrderDateCustomerTotal
#72Garcia-Wood$66,546.57
#73Lindgren & Co$12,840.00
#74Okafor Studio$3,215.90

Editing cells

data-edit on a header makes its cells editable. Click a value (or focus it and press Enter, or start typing), change it, then Enter or click away to save; Escape puts it back. The editor follows the column's data-type (Status is a choice, Review a date), or a template.canon-data-table-editor in the header: Owner is a Combobox, Target a number field that can't be empty or below 0. Each change fires canon-edit; here the page cancels it to save on its own, then answers canon-saved, or canon-save-failed for a target of 0. KPI isn't editable, nor is the last row's Review (data-edit="none"). Specification: docs/components/data-table-editing.md

Hiring KPIs
KPI Owner Target Actual Status Review
Time to hireAda Lovelace30 days34 daysAt risk
Offer acceptanceGrace Hopper85%88%On track
First-year retentionKatherine Johnson92%84%Off track
Training hoursAda Lovelace24 h26 hOn track

Edit a value to see its event.

Editing in a form

In a form with a Save Bar, each editable cell holds its value in a field (<input hidden name>): an edit changes the field, the Save Bar counts it and the cell is marked; Discard puts every value back, Save sends them together. A switch (or checkbox) in an editable column is changed where it is, and counts the same way.

Team seats
TeamSeatsPlanBilling contactAuto-renew
Design12Businessops@globex.com
Engineering48Enterpriseeng-admin@globex.com
Research6Starterlab@globex.com

Pinned columns

data-pin on a header keeps its column in view while the others scroll; here, User. The select column and the actions column are always pinned. A pinned column shows a line at its edge; the last one casts a shadow while rows scroll under it. Scroll the table sideways.

Users
UserEmailPhoneCompanyCityCountryDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com+1 202 555 0143Kertzmann LLCAustinUnited States$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com+44 20 7946 0958Hills GroupLondonUnited Kingdom$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com+49 30 901820Boyle IncBerlinGermany$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com+33 1 70 18 99 00Ward & SonsParisFrance$436.68Waiting
Mrs. Jo Emardjovany66@hotmail.com+81 3 6823 1234Kuhic LtdTokyoJapan$984.24Delivered

Sorting by the app

Without data-local, a sort button fires canon-sort (detail: { index, key, direction }) and updates aria-sort; the app loads the rows in that order. Cancel the event to keep the current order. Sort values come from a cell's data-value, else its <time datetime>, else its text.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com$436.68Waiting

Press a header to sort.

Lines, stripes, hover, frame

A Data Table takes Table's options on its frame: here data-lines="grid", data-striped and data-hover. A selected row is a step darker than a stripe; the row under the pointer is darker still.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Shari Feeney PhDcecelia_erdman@yahoo.com$436.68Waiting
Mrs. Jo Emardjovany66@hotmail.com$984.24Delivered
Lauren Monahanjermaine.corkery@gmail.com$916.69In delivery
Antoinette Wilkinsonmarcos.zulauf@gmail.com$378.25Cancelled
Glen Tremblayora_gutmann@gmail.com$357.93Ready
Marjorie Mertzjoshua_hodkiewicz@yahoo.com$954.96In delivery
Janet Hyattgraham.cassin@yahoo.com$569.18Delivered
Dwayne Kubalva.kemmer@gmail.com$1,204.50Waiting
Rosa Larkinverna_hand@hotmail.com$88.40Delivered

Loading, empty, no results, error

While the app loads, aria-busy="true" on the data table: skeleton rows stand in for the body, as many as a page. When there's nothing to show, one row holds an Empty State (canon.js spans it across the columns): nothing yet, nothing matching the filters, or an error with a way to try again.

Users
UserEmailDateAmountStatus
Users
UserEmailDateAmountStatus

No users yet

People you invite will show up here.

Users
UserEmailDateAmountStatus

No matching users

Try other words, or clear the filters to see everyone.

Users
UserEmailDateAmountStatus

Couldn't load users

Something went wrong on our side. Try again in a moment.

Size

data-size on the data table or a container sizes the table, its controls and its pagination together.

Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled
Users
UserEmailDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com$235.71Cancelled

Edge cases

Right to left, pinned columns stick to the right and the actions column to the left; their shadows fall the other way.

المستخدمون
UserEmailPhoneCompanyCityCountryDateAmountStatus
Edwin Muellertyrese_nicolas@gmail.com+1 202 555 0143Kertzmann LLCAustinUnited States$495.90Waiting
Suzanne Jacobicindy_murphy41@yahoo.com+44 20 7946 0958Hills GroupLondonUnited Kingdom$662.02Ready
Kellie Schoentroy.lubowitz@gmail.com+49 30 901820Boyle IncBerlinGermany$235.71Cancelled