Tables
Simple table
| Name | Date | Last seen |
|---|---|---|
| Project Alpha | 2026-01-10 | |
| Project Beta | 2026-02-18 | |
| Project Gamma | 2026-03-25 |
Wider than the room
| Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 | Column 9 | Column 10 | Column 11 | Column 12 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough |
| A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough |
| A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough | A value long enough |
Table with actions
Striped rows, lit under the pointer
Rows that can be ticked
A box at the head of each row, one in the header for them all, and the actions above: they post the ticked rows to their own address, and stay out of reach while nothing is ticked.
Files, a total, an action on every row
Paths read by their name, the folders before it cut from their start. The bar ends on how many rows there are, and an action marked `all` works with nothing ticked — it takes every row, and leads the bar when it is the one expected.
| File | |
|---|---|
| 03-DOCUMENTS/QAL - Syst Document/Obsolète/QAL-D-12-identification-and-validation-of-quality-system-software-v1.md | |
| 05-INSTRUCTIONS/RES/RES-I-02-it-access-change-v2.md | |
| README.md |
Filters
A bar of filters at the head of the table, one discreet menu each, saying what it narrows to once it does. On the server they live in the page's query — each option is a link — and the controller narrows the rows from it; in vue they are a value handed to the page for its api, or applied by the table to the rows it already has. Each option is a box — round for a choice of one — coloured by its tone when it has one, a status or a category.
| Name | Owner | State |
|---|---|---|
| Alpha | design | open |
| Beta | platform | closed |
| Gamma | design | closed |
| Delta | support | open |
Sorting
A header that sorts is a link on the server and a button in vue: ascending, descending, then back to the order the page declared, which the list opens on and which its arrow shows from the start. Empty dates go last both ways, and names compare the way the language orders them. Here the table sorts the rows it was given itself; a controller paging its list reads the same query instead.
| Name | City | Last measurement | Actions |
|---|---|---|---|
| Adam Petit | Angers | ||
| Zoé Martin | Zürich | ||
| Eric Bernard | Lyon | ||
| Élodie Durand | Évry | ||
| Basile Leroy | Écully |
Sorting in the browser, from twig
`vue: true` hands the same columns and rows to the vue twin: it sorts and searches the whole list in the browser, with no page load. For a list the page holds whole — a short one, or one no api serves.
Actions in a select
The same bar when there are enough actions to crowd it: one is chosen, then applied.
Link and icon cells
| Source | State |
|---|---|
| Source Alpha | |
| Source Beta |
Loading state
| Source | Updated at | Actions |
|---|---|---|
|
|
||
Empty state
| Source | Updated at | Actions |
|---|---|---|
| No data available. | ||
Column alignment
| Name (left) | Status (center) | Amount (right) |
|---|---|---|
| Alpha | Centered | 42.00 € |
| Beta | Centered | 128.50 € |
| Gamma | Centered | 7.99 € |
Codes, figures and totals
`cell: 'code'` sets an identifier in the mono face; `cell: 'number'`, or a `unit`, writes a figure in the page's locale. `negative: true` draws a figure below zero in the error tone, its minus sign saying it too. `totals` is a row the page hands over, drawn under the others — the table adds nothing up, holding one page or a filtered list. Drawn by the server, then by vue.
| Code | Item | Net supply | Area |
|---|---|---|---|
VS-2041 |
Atlas | 12 | 18.5 m² |
LO-0007 |
Boréal | -4 | 9 m² |
VS-1180 |
Cyprès | 0 | 6.5 m² |
LO-0315 |
Dune | -11 | 22.5 m² |
| Total | -3 | 56.5 m² |
From markdown
A table written in markdown and passed through `markdown_ds`: the columns, their alignment and the markup of each cell are read from the document, and the table is drawn here like any other. `markdown` keeps the plain `<table>`, for whatever is not a page — a mail, a feed.
| Name | Status | Amount |
|---|---|---|
| Alpha | ready |
42.00 € |
| Beta | 128.50 € | |
| Gamma | pending | 7.99 € |
Group rows
A row carrying only a group is not a row: it is the line between two runs of them, given a word. It spans the table and names what follows — the same reading as a menu separator.
| Name | Date |
|---|---|
| First group | |
| Project Alpha | 2026-01-10 |
| Project Beta | 2026-02-18 |
| Second group | |
| Project Gamma | 2026-03-25 |
Status cells
A state is a circle, never a colour someone picked: the cell takes a type name, or a type with a count and a title, and draws the status icon the rest of the system draws. Nothing to style in the page.
| Pipeline | Build | Tests | Deploy |
|---|---|---|---|
| Project Alpha | 42 | ||
| Project Beta | 3 | ||
| Project Gamma |
Sticky header
A long table is read column by column as much as row by row. With `sticky`, the header stays in view while the rows scroll under it; a page with something of its own pinned at the top says how far down in `--table-sticky-top`.
| # | Name | State |
|---|---|---|
| 1 | Row 1 | |
| 2 | Row 2 | |
| 3 | Row 3 | |
| 4 | Row 4 | |
| 5 | Row 5 | |
| 6 | Row 6 | |
| 7 | Row 7 | |
| 8 | Row 8 | |
| 9 | Row 9 | |
| 10 | Row 10 | |
| 11 | Row 11 | |
| 12 | Row 12 |
A table in a zone of its own
A `zone--table` zone is given to the table whole: what drives it at the top, its pages at the foot, out of what scrolls, and between them the table's ground down to the bottom of the zone, even for three rows. Any table goes in it, written by the server or by a vue. With `natural`, as the one on the left, the table keeps the width of its columns, neither stretched nor squeezed.
| # | Name | State |
|---|---|---|
| 1 | Row 1 | |
| 2 | Row 2 | |
| 3 | Row 3 |
Vue entity table
Vue table with selection
The same contract on the client: the ticked keys come back through v-model:selected, each action is emitted as bulk-action, and one with an address is posted as the server table posts it. These have none, so the line below says what would have been done. Three rows a page, the total at the end of the bar, and Archive all needing nothing ticked.
Pagination without a total
When the API does not return a total, the pager falls back to previous/next.
Pagination, drawn by the server
`pagination(page, pages_count)` draws the pages of a list as links: each keeps the route and the query of the page it is on — a search, a sort — and changes only `page`, counted from 1. The numbers shown are the vue pager's: the first, the last, the current one and its neighbours. `compact` keeps previous and next around the page number; `route` and `params` page through another address.