enhancement
major
minor
major
minor
major
#29625
TL Views: a page layout of weighted columns (main 2/3, side 1/3) that reflows to one column on a narrow viewport; the split-panel keeps its sashes and clips the side pane at 400 px
Problem
The ticket page of the issue tracker tl-dev (ticket.view.xml) is a <split-panel orientation="vertical"> (header pane 25 %, body 75 %) whose body is a <split-panel orientation="horizontal"> (main column 65 %, side column 35 %). Both are resizable="true". That is the only way the view layer offers to put a wide main column next to a narrow side column.
Measured at 1600×900 (engine snapshot build 37 of 2026-09-16): the top pane is 210 px high while its form card is 268 px, so the Status and Type rows of the header sit below the fold and scroll inside the pane; the sashes are 4 px bars with row-resize / col-resize cursors that a reader of a ticket has no reason to drag.
Measured at 400×800 (a phone): the two splits stay as they are. The body's horizontal split gives the main column 320 px and the side column 240 px starting at x = 324, so the side column's right edge is at 564 px, 164 px beyond the viewport; its .tlPanel__content reports clientWidth == scrollWidth == 240, so the clipped part is unreachable, and the page has no horizontal scroll (documentElement.scrollWidth == clientWidth == 400). Labels are cut to "Klas…", "Lösun", "Priori". The header pane is 185 px high and shows the ID and one label of its four fields.
What exists and why it does not serve:
- <grid min-column-width max-columns>: equal columns only, a child cannot span or weigh.
- <stack direction="row">: no wrapping and no weight per child; <panel width="…"> is a preferred width that never grows, so a 2/1 pair does not fill the row and does not fold.
- <adaptive-detail>: a master-detail with a hard-wired 32/68 split and a drill-in on the compact side, not a page layout.
- <dashboard>: tiles weigh their width and the grid folds to one column, but the tiles are meant to be reordered and (after #29613) have a definite row height, which is wrong for a page whose main column is long content that scrolls with the page.
Request
A page layout with weighted columns that reflows: the columns share the width by weight (main 2, side 1) while the viewport carries them side by side, and stack in declaration order below a breakpoint - the counterpart of the <split-panel> for reading pages, where no sash is wanted. Either a column-span / weight on a <grid> child with the grid's existing fold-to-one-column behaviour, or a <columns> element of <column weight="2"> children. The page as a whole scrolls; a column is as tall as its content.
The app change that then lands: the ticket page becomes a column <stack> of the header form and such a two-column layout, with no split panel, so the header takes the height its four fields need and the page works on a phone.
Lösung
A <columns> element of <column weight="…"> children:
<columns breakpoint="48rem" gap="default"> <column weight="2"> … main content … </column> <column> … side content … </column> </columns>
- <column> (ColumnElement) is a container: its children stand below each other in the column. weight (a positive integer, 1 by default) is the column's share of the row.
- <columns> (ColumnsElement) takes breakpoint (a CSS length, 48rem by default, the compact threshold <adaptive-detail> uses as well) and gap (compact / default / loose, as <stack> and <grid>).
- While the element itself - its container, not the viewport, so a nested layout folds on its own width - is at least breakpoint wide, the columns stand side by side and share the width by weight (2 and 1 give 2/3 and 1/3). Below it they stand below each other in declaration order, each full width. The fold is pure CSS (a wrapping flex row whose items take flex: <weight> 1 calc((breakpoint - 100%) * 999)), no measuring script.
- A column is as tall as its content; the element takes no part in the fill contract, so a page built of it scrolls as a whole. No sashes.
Technically: ReactColumnsControl (com.top_logic.layout.react, a ReactLayoutControl rendering the TLColumns component) carries the weights, breakpoint and gap; a column's content is a vertical ReactStackControl. Documented in docs/faq/react-view-layer.md; a demo page demo/columns-demo.view.xml in com.top_logic.demo.react.