Turning swimlanes on for an object-kanban removes the status column headers from the screen. They stay in the DOM, at the right coordinates, and paint nothing — so the board becomes a grid of cards with no way to tell Open from Done except by dragging one and watching where it lands.
Measured on @objectstack/console17.2.0, served by @objectstack/cli 17.2.0, in Chromium 1194 at 1600×1000, against a live pnpm demo of the duly app (duly_task.board, groupByField: 'status').
Reproduce
Author a kanban list view and give the view (not the kanban block) a grouping:
board: {type: 'kanban',data: {provider: 'object',object: 'duly_task'},columns: [{field: 'subject'},{field: 'due_date'},{field: 'owner'},{field: 'source'}],kanban: {groupByField: 'status',columns: ['subject','due_date','owner','source']},grouping: {fields: [{field: 'source'}]},// ← swimlanes on}The relay derives the swimlane from swimlaneField || grouping.fields[0].field, so this is the authorable route (KanbanConfigSchema is strict and rejects kanban.swimlaneField, so it is the only one).
What happens
Lanes render correctly — ▼ CATALOG (19) and siblings, cards inside them. The column headers do not.
With groupingpresent, the five titles are in the DOM but invisible:
Open top 233 left 581 <span>
In progress top 233 left 883 <span>
Done top 233 left 1248 <span>
Skipped top 233 left 1575 <span>
Cancelled top 233 left 1899 <span>
Their ancestors, from the title outwards:
span .text-xs.sm:text-sm.font-semibold.tracking-wider height 16
div .w-[85vw].sm:w-80.shrink-0.text-center height 0 ← collapsed
div .flex.gap-3.sm:gap-4.pl-36.sm:pl-44.overflow-x-auto height 0 ← collapsed
document.elementFromPoint() at a title's own centre returns the lane collapse <button> (▶catalog(19)) sitting behind it, and a screenshot cropped to that band shows blank space above the first lane. Computed style on the title is unremarkable — color: oklab(0.403 -0.049 -0.039 / 0.9), font-size: 14px, opacity: 1, visibility: visible — so this is layout, not paint: the header row's flex container measures 0 high and its children collapse with it.
With groupingabsent and nothing else changed, the same board renders the titles as real elements at the same band and they are visible:
Open top 243 left 273 <h3>
In progress top 243 left 609 <h3>
Done top 243 left 945 <h3>
Skipped top 243 left 1281 <h3>
Cancelled top 243 left 1617 <h3>
Note the tag change — <h3> in the plain board, <span> inside the swimlane header row — so the two paths build the header row differently and only the swimlane one collapses.
Why it matters
A kanban's columns are its semantics. Without the labels the swimlane board reads as an unordered card wall: the lane tells you the caliber of the work and nothing tells you its state. It also degrades silently — the view validates, the lanes look right, and the missing row is easy to read as a design choice rather than a bug.
Practical effect downstream: objectstack-ai/duly#108 asked for swimlanes by source on its board (a pre-sales demo screen). Swimlanes work and were dropped anyway, because a board with no column titles is worse than a board with no lanes; the card face carries source instead. The one-line re-enable is sitting in a comment in src/views/task.view.ts waiting on this.
Expected
The swimlane header row keeps its height and paints the column titles above the lanes, as the non-swimlane board does.
Turning swimlanes on for an
object-kanbanremoves the status column headers from the screen. They stay in the DOM, at the right coordinates, and paint nothing — so the board becomes a grid of cards with no way to tell Open from Done except by dragging one and watching where it lands.Measured on
@objectstack/console17.2.0, served by@objectstack/cli17.2.0, in Chromium 1194 at 1600×1000, against a livepnpm demoof thedulyapp (duly_task.board,groupByField: 'status').Reproduce
Author a kanban list view and give the view (not the
kanbanblock) agrouping:The relay derives the swimlane from
swimlaneField || grouping.fields[0].field, so this is the authorable route (KanbanConfigSchemais strict and rejectskanban.swimlaneField, so it is the only one).What happens
Lanes render correctly —
▼ CATALOG (19)and siblings, cards inside them. The column headers do not.With
groupingpresent, the five titles are in the DOM but invisible:Their ancestors, from the title outwards:
document.elementFromPoint()at a title's own centre returns the lane collapse<button>(▶catalog(19)) sitting behind it, and a screenshot cropped to that band shows blank space above the first lane. Computed style on the title is unremarkable —color: oklab(0.403 -0.049 -0.039 / 0.9),font-size: 14px,opacity: 1,visibility: visible— so this is layout, not paint: the header row's flex container measures 0 high and its children collapse with it.With
groupingabsent and nothing else changed, the same board renders the titles as real elements at the same band and they are visible:Note the tag change —
<h3>in the plain board,<span>inside the swimlane header row — so the two paths build the header row differently and only the swimlane one collapses.Why it matters
A kanban's columns are its semantics. Without the labels the swimlane board reads as an unordered card wall: the lane tells you the caliber of the work and nothing tells you its state. It also degrades silently — the view validates, the lanes look right, and the missing row is easy to read as a design choice rather than a bug.
Practical effect downstream:
objectstack-ai/duly#108asked for swimlanes by source on its board (a pre-sales demo screen). Swimlanes work and were dropped anyway, because a board with no column titles is worse than a board with no lanes; the card face carriessourceinstead. The one-line re-enable is sitting in a comment insrc/views/task.view.tswaiting on this.Expected
The swimlane header row keeps its height and paints the column titles above the lanes, as the non-swimlane board does.