Keep a button at its label's width in a stack and a form

<x-stack> stretches its children across by default and <x-form> is a
one-track grid, so a button written directly in either drew as a
full-width pill. M3 keeps a button's width "dynamic to fit label" and
says not to "stretch buttons into long flat shapes on large windows".
A button there now sits at the start edge at its own width; a stack
aligned start, centre or end is untouched, and an application's own
width still wins (a cap on the button itself was rejected for exactly
that: it would have limited an app's inline-size, which CascadeTest
guards). Chromium test in both directions, failing without the rules.
Decided with the user (plan step 46).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 12:56:45 +02:00
co-authored by Claude Opus 5
parent f5f040516e
commit 92d3d761f3
8 changed files with 58 additions and 5 deletions
@@ -611,7 +611,7 @@ With `scroll`, M3's overflow affordance is drawn for you: the edge the row can s
### `<x-form>`
A one-column grid of fields with an `actions` slot at the foot (the slot takes its own `class`); `separator` draws a divider above the actions.
A one-column grid of fields with an `actions` slot at the foot, end-aligned (the slot takes its own `class`); `separator` draws a divider above the actions. Put a form's buttons in `actions`; a button written among the fields keeps its label's width at the start edge rather than stretching across.
```blade
<x-form wire:submit="save">
@@ -925,7 +925,7 @@ A tonal region: `<x-surface level="surface-container-low" padding="space300" cor
#### `<x-stack>`
Children one under another inside a pane: `<x-stack gap="space200">…</x-stack>`. `align` across it: `stretch` (default), `start`, `center`, `end`.
Children one under another inside a pane: `<x-stack gap="space200">…</x-stack>`. `align` across it: `stretch` (default), `start`, `center`, `end`. A button keeps its label's width at the start edge even when the rest stretch: M3 keeps a button's width dynamic and never stretches one into a long flat shape. Widen one only in your own CSS, and only with a reason.
#### `<x-row>`
+8 -1
View File
@@ -6,7 +6,10 @@
* floors at its content's min-content, so on a phone a wide field would push the form past its
* pane. Rows take their content's height. 16px (`space200`) between fields, because a text field
* floats its label half above its outline and any less lets the hint under one field run into the
* label of the next.
* label of the next. A button written among the fields keeps its label's width at the start edge,
* where the grid would stretch it across: M3 keeps a button's width "dynamic to fit label" and
* says not to "stretch buttons into long flat shapes"
* (docs/reference/m3/components-actions-communication-containment.md § Buttons).
*
* The actions wrap, end-aligned, 8px (`space100`) apart M3's gap between buttons in a row. A
* caller's class on the `actions` slot lands on the row and outranks this layer.
@@ -27,6 +30,10 @@
gap: var(--md-sys-measurement-space200);
}
[data-md-form] > [data-md-button] {
justify-self: start;
}
[data-md-form-actions] {
display: flex;
flex-wrap: wrap;
+8 -1
View File
@@ -2,7 +2,10 @@
* <x-stack>: its children one under another, in a pane.
*
* A flex column, stretched across the stack's width unless `data-md-align` says `start`, `center`
* or `end`. The space between the children is `--md-gap` (spacing.css), one of M3's spacing
* or `end` except a button, which keeps its label's width at the start edge: M3 keeps a button's
* width "dynamic to fit label" and says not to "stretch buttons into long flat shapes on large
* windows" (docs/reference/m3/components-actions-communication-containment.md § Buttons). An
* application's own width or `align-self` on it still wins. The space between the children is `--md-gap` (spacing.css), one of M3's spacing
* tokens and none by default; M3 groups with proximity, so the gap is the grouping
* (docs/reference/m3/foundations.md § Layout Grids & spacing). M3 defines no in-pane arrangement
* component; this is the neutral one, beside <x-row> and <x-grid>.
@@ -26,6 +29,10 @@
gap: var(--md-gap);
}
[data-md-stack]:is(:not([data-md-align]), [data-md-align='stretch']) > [data-md-button] {
align-self: start;
}
[data-md-stack][data-md-align='start'] {
align-items: flex-start;
}
+2 -1
View File
@@ -4,7 +4,8 @@
`gap` is a spacing token's name, `space25` `space900` (docs/reference/m3/styles-supplement.md
§ Spacing), and none when left out or unknown. `align` places the children across the stack:
`stretch` (the default), `start`, `center` or `end`.
`stretch` (the default), `start`, `center` or `end`. A button keeps its label's width even
when the rest stretch, as M3 asks.
M3's layout has no arrangement component inside a pane its "column" is a grid column so
this is the package's neutral one, beside `<x-row>` and `<x-grid>`. It takes `as`,