Standardize layout component props: derive a shared prop set for Stack/Grid/Center/Section/Layout/FormLayout
- Dominant language
- TypeScript
- Stars
- 13k
- Forks
- 1.1k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 690
Description
## Summary
Astryx's layout components (`group: 'Layout'` — `Stack`, `Grid`, `Center`, `Section`, `Layout`, `FormLayout`) have **no shared prop standard**. Each evolved its own vocabulary for the same concerns (sizing, spacing, alignment, escape hatches), and the gaps get filed one component at a time. This issue derives a **standard layout prop set** and tracks aligning the components to it.
The wiki [API Conventions](https://github.com/facebook/astryx/wiki/API-Conventions) documents **Input Component Props** and `BaseProps` in detail, but has **no Layout Component Props section** — so the common vocabulary was never recorded anywhere. This adds it.
## Findings: current inconsistencies
| Concern | Inconsistency across the 6 layout components |
|---|---|
| **Escape hatches** | `Stack`, `Grid`, `Center`, `FormLayout`, `StackItem` **re-declare** `xstyle`/`className`/`style` even though `BaseProps` already provides them (the Component Auditor flags this as redundant). `Section`/`Layout*` correctly inherit. |
| **`ref` type** | Mixed: some use `React.Ref`, others `React.Ref`, re-declared inconsistently. |
| **Sizing** | `Stack`/`Grid`/`Center` use `SizeValue` for `width`/`height`. `Section` adds `maxWidth`/`minHeight` only. `Layout`/`LayoutHeader`/`LayoutPanel` use raw `number \| string`, and `Layout` uses `contentWidth: number`. No component exposes the full `min/max` set. |
| **Spacing** | `gap` (Stack/Grid) vs `padding` (Section/Layout) — both `SpacingStep`, but no documented split of which applies where. |
| **Alignment** | `Stack`: `hAlign`/`vAlign` + `justify`/`align` aliases. `Grid`: its own `GridAlignment`. `Center`: `axis`. Three different alignment vocabularies. |
| **Dividers** | `Section`: `dividers: Array<'top'\|'bottom'\|'start'\|'end'>`. `Layout*`: `hasDivider: boolean`. No documented rule for which shape to use. |
## Related open issues (same root cause)
All of these are requests for layout props that a standard would systematize:
- #2623 — `overflow` + flex `grow`/`shrink`/`basis` on Section/Stack/HStack/VStack
- #2613 — `isSticky` / `stickyOffset` on layout primitives
- #2625 — `maxWidth`/`shellWidth` to cap the `Layout` shell
- #2594 — page-surface props (`background`, `padding`) on `Center`
- #2798 — responsive `ratio` on `AspectRatio`
- #2753 — child sizing/positioning props on `AspectRatio`
- #2987 — runtime pixel sizing primitive for resizable panels
## Proposed standard
### A. Universal — every layout component
| Prop | Type | Notes |
|---|---|---|
| `children` | `ReactNode` | |
| `ref` | `React.Ref` | one consistent type |
| `xstyle` | `StyleXStyles` | **inherited from `BaseProps` — never re-declare** |
| `className` | `string` | inherited from `BaseProps` |
| `style` | `React.CSSProperties` | inherited from `BaseProps` |
### B. Sizing — box primitives (Stack, Grid, Center, Section)
`width`, `height`, `minWidth`, `maxWidth`, `minHeight`, `maxHeight` — all `SizeValue` (number = px, string as-is). `Layout*` migrates from `number | string` to `SizeValue`.
### C. Spacing
- `gap` (+ `rowGap` / `columnGap` for Grid) — `SpacingStep`, on flex/grid containers
- `padding` (+ `paddingBlock` / `paddingInline`) — `SpacingStep`, on surface containers
### D. Alignment — flex/grid containers
- `align` — cross axis (`align-items`): `'start' | 'center' | 'end' | 'stretch'`
- `justify` — main axis (`justify-content`): `'start' | 'center' | 'end' | 'between' | 'around' | 'evenly'`
`hAlign`/`vAlign` remain Stack's direction-aware sugar; `align`/`justify` is the cross-component standard.
### E. Flow & flex-item control — reserved names (incremental implementation)
These are the capability gaps the related issues ask for; the standard reserves consistent names so they land uniformly:
`overflow` (`'visible'|'hidden'|'clip'|'auto'|'scroll'`), `isScrollable` (already on `LayoutContent`/`LayoutPanel` — promote), `grow` (`boolean|number`), `shrink` (`boolean|number`), `basis` (`SizeValue`), `isSticky` (`boolean`), `stickyOffset` (`SpacingStep`).
### F. Dividers — documented rule
- `hasDivider: boolean` when there's a single implied edge (Layout areas)
- `dividers: Array<'top'|'bottom'|'start'|'end'>` when edges are selectable (Section)
## Plan
1. Add a **"Layout Component Props"** section to the API Conventions wiki (mirrors the existing "Input Component Props" section).
2. **Draft PR** normalizing the existing components to the standard (safe changes first: drop redundant escape-hatch re-declarations, unify `ref` types, migrate sizing to `SizeValue`, add the missing `min/max` sizing props, align the alignment vocabulary).
3. Capability props (Tier E) implemented incrementally, each closing its linked issue.
Contributor guide
Assessment
This issue has not been assessed yet.