Tables

Tables

Simple table

NameDateLast seen
Project Alpha 2026-01-10
Project Beta 2026-02-18
Project Gamma 2026-03-25

Wider than the room

A table whose columns ask for more than the page has is drawn at the width it needs and overflows to whatever scrolls around it — the zone, the page —, never with a scrollbar of its own. Asked for (`scroll: true`), as here, it scrolls sideways in its own frame and the page around it stays put: for a table among other things in a container that does not scroll. A sticky table gives this up: a header sticking to the page and a frame scrolling on its own cannot be had together.
Column 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8Column 9Column 10Column 11Column 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

SourceUpdated atActions
Source Alpha 2026-01-12
Source Beta 2026-02-20

Striped rows, lit under the pointer

SourceUpdated atActions
Source Alpha 2026-01-12
Source Beta 2026-02-20
Project Alpha 2026-01-10
Project Beta 2026-02-18
Project Gamma 2026-03-25

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.

0 selected
SourceUpdated atActions
Source Alpha 2026-01-12
Source Beta 2026-02-20
Project Alpha 2026-01-10

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.

0 selected 3 in total
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.

4 in total
NameOwnerState
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.

5 in total
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.

0 selected
SourceUpdated atActions
Source Alpha 2026-01-12
Source Beta 2026-02-20
Project Alpha 2026-01-10

Link and icon cells

SourceState
Source Alpha
Source Beta

Loading state

SourceUpdated atActions

Empty state

SourceUpdated atActions
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.

CodeItemNet supplyArea
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.

NameStatusAmount
Alpha ready 42.00 €
Beta draft 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.

NameDate
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.

PipelineBuildTestsDeploy
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`.

#NameState
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.

#NameState
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.

Vue date formatters