Form: let a responsive page form take its width from the parent - #1187
Conversation
Hello jeanmarcmilletscality,My role is to assist you with the merge of this Available options
Available commands
Status report is not available. |
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list: |
`container-type: inline-size` implies `contain: inline-size`, so a `responsive` Form's contents stop contributing to its intrinsic width. As a content-sized flex item it therefore resolved to 0 and every child overflowed it — and its container query, measuring a 0px box, matched permanently, pinning every such form to the stacked layout. Pair the containment with `flex: 1 1 auto; min-width: 0`, the way LeftPanel/RightPanel already do. Separately, the page layout's three columns (header, scroll area, footer) were pinned to `width: 45rem`, so below that the fields, the section actions and the fixed footer sat outside the page with no way to reach them. Make it a cap: `width: 100%` with `box-sizing: border-box`, and carry the column padding in the cap so the *content* still gets exactly 45rem. `Box container` had the same containment trap with no width companion, so it gets `min-width: 0` too. A page form's columns keep centring in the room they have (`margin: 0 auto`, unchanged): 646px at x=397 in a 1440 viewport, exactly as before. A form in a flex row now centres too, where before its 0px box left the columns spilling out from the row's left edge. ResponsivePageFormAlignment renders both alignments on one width control, for whenever that is revisited. Verified in Storybook (ResponsivePageFormInFlexRow) at content boxes 1420/1200/1000/900/800/768/700/600: zero overflow throughout, columns aligned, footer always inside the box, and the 45rem cap held at >= 1000.
f8e567d to
ba01ece
Compare
Waiting for approvalThe following approvals are needed before I can proceed with the merge:
Peer approvals must include at least 1 approval from the following list: |
|
/approve |
In the queueThe changeset has received all authorizations and has been added to the The changeset will be merged in:
There is no action required on your side. You will be notified here once IMPORTANT Please do not attempt to modify this pull request.
If you need this pull request to be removed from the queue, please contact a The following options are set: approve |
|
I have successfully merged the changeset of this pull request
Please check the status of the associated issue None. Goodbye jeanmarcmilletscality. |
TL;DR: A
responsivepageFormplaced in a flex row collapsed to a 0px-wide box, and its content columns were pinned to45remso they could not narrow — putting the fields, the section actions and the footer outside the page below ~1000px. The form now takes its width from its parent and treats45remas a cap, so it stays usable down to ~600px with no change to how a page form looks today.Component:
Form(page layout),BoxDescription:
A
pageForm withresponsivecollapses to a 0px-wide box in any flex row, and its content columns are pinned towidth: 45remso they cannot narrow below that. Together those two rules make a wizard-shaped page (step sidebar + form) unusable below ~1000px: the fields, the section actions and the Save/Continue footer sit outside the page with no way to reach them.It is the first gap a consumer hits when it puts a page form in a flex layout, and it is currently worked around downstream with a local width wrapper.
Design: No visual change to a page form as it ships today (measured below). No API change.
Breaking Changes:
🧠 Approach
Two independent rules, both in
Form.component.tsx.1. Containment removed the form's own width.
container-type: inline-sizeimpliescontain: inline-size, so aresponsiveForm's contents stop contributing to its intrinsic width. As a content-sized flex item it therefore resolves to 0px — and its own container query, measuring that 0px box, matches permanently, which silently pinned every flex-parented responsive form to the stacked label layout at all widths. The fix is the pairinglayout/v2/panels.tsxalready uses forLeftPanel/RightPanel:Before:
After:
2. The page columns were pinned, not capped.
BasicPageLayoutis extended by the header, the scroll area and the footer, so it decides how wide a page form's content is:Before:
After:
Two things are load-bearing there and are the part worth reviewing:
box-sizing: border-boxis required bywidth: 100%, or the content-boxpadding-rightoverflows the parent by exactly that padding.calc(45rem + 16px), not45rem. Underborder-boxa bare45remcap would shrink the column from 646px to 630px — the padding used to sit outside the pinned width. Carrying it in the cap keeps exactly the same 45rem of content as before.📐 Measured behaviour
Content box narrowed with the viewport held constant — the case a container query exists for, and the reason a media query would not have caught any of this: a host application can shrink the box it gives an app without the viewport changing at all.
The 45rem cap still holds wherever there is room for it (≥1000), and the footer stays inside the box at every width. A page form that is not in a flex row is untouched: 646px column at x=397 in a 1440 viewport, identical to
development/1.0.📸 Screenshots
Templates/Form → ResponsivePageFormInFlexRow— apageform in a flex row beside a 324px step sidebar.At a 780px content box — the drawer-open case. The
Continuebutton is gone,Optional helper textis clipped toOption, the required-fields legend is missing, and the row scrolls sideways by 305px. After: the form box is 341px instead of 0, and everything is inside it with no scrollbar.development/1.0At a 1440px viewport — the part that is easy to miss. The form's own
@container (max-width: …)query was measuring its 0px box, so it matched permanently and everydirection="horizontal"field row was pinned stacked at every width. The fields only become side-by-side once the form has a real width.development/1.0— labels above their inputs, with 646px of unused room to the right:This PR — side-by-side, as
direction="horizontal"asks:🔧 Usage
No API change —
responsiveis unchanged, and this is what now works:(from
stories/form.stories.tsx › ResponsivePageFormInFlexRow, added here)A consumer that worked around the collapse with its own width wrapper can drop it.
🔍 Review focus
src/lib/components/form/Form.component.tsx › BasicPageLayout— theborder-box+calc(45rem + 16px)arithmetic. Getting the+ 16pxwrong is a silent 16px narrowing of every page form in the fleet.src/lib/components/form/Form.component.tsx › StyledForm—flex: 1 1 automeans aresponsivepage form now grows to fill a flex parent instead of being content-sized. Intended, and the only way the container query can measure anything, but it is the behavioural change here.src/lib/components/box/Box.ts › Box— same containment trap, socontainernow also emitsmin-width: 0. Noflexon this one:Boxis a general primitive and stays unopinionated about where its definite width comes from.🧪 How to test
npm run storybook, open Templates/Form → ResponsivePageFormInFlexRow.responsivearg off and on — with it on, the labels are side-by-side at wide widths (before this PR they were stuck stacked, because the query was reading a 0px box).🧭 Follow-up
responsive. That deletion is this PR's real acceptance test.margin: 0 auto, centred). A form in a flex row now centres its capped columns in the row, where before its 0px box left them spilling from the row's left edge. Whether they should instead stay flush with a neighbouring sidebar is a design decision, so it is deliberately not part of this fix.What changed
Form.component.tsxcarries the whole fix in two rules —StyledForm's containment block andBasicPageLayout's width.Box.tsgets themin-width: 0companion for itscontainerprop.stories/form.stories.tsxadds the story above, and generalises the existingResizeFramehelper with optionalminWidth/heightrather than adding a second near-identical frame.Deliberately not here: the
SearchInputfluidgap (CUI-41), the label/field grid squeeze order, and the table/toast gaps — separate PRs, one surface each.