The parent container's layout rules determine each child's final position and size. Child settings such as width, height and weight express sizing requirements; the container interprets them as fixed sizes, preferred sizes, minimum sizes or allocation weights according to its layout policy. Container behavior takes precedence when resolving these settings.
For example, a Grid child fills its assigned cell, including an expanded span. A declared height of 60 remains a minimum rather than preventing the child from filling a taller cell. HBox and VBox instead use the linear expansion priorities, weights and cross-axis rules below; this principle does not make every child stretch or discard its size requirements.
.layout(width=..., height=...) declares a desired size, not a hard
maximum. A desired dimension sets that axis's automatic expansion priority to 0;
the other axis keeps its own policy. A positive weight still explicitly requests
expansion on the parent's allocation axis (both axes in Grid). Parent allocation,
native content constraints and explicit toolkit overrides determine the final size.
.layout(minWidth=..., minHeight=...) supplies minimum-size hints
without setting a desired size or lowering expansion priority. A desired size may
also supply a minimum hint; the larger of the two hints wins. A minimum must never
be copied back into width/height. Textual uses
.tLayout(minWidth=..., minHeight=...) in terminal cells.
For example, an unweighted Canvas has priority 4 on both axes.
Canvas(paint).layout(width=160) requests a compact width while its
height can expand; .layout(minWidth=160) retains automatic expansion
on both axes. Native padding, natural sizes and ancestor constraints can still
produce different pixel sizes; Flet's parent constraints can clamp size hints.
wx is the reference for an explicit implementation of this sizing policy: per-axis expansion priorities, competition among siblings, weighted space allocation, and cross-axis alignment. Use its layout implementation as a guide when a backend needs to implement these rules itself. The policy in this document remains the common contract.
PySide6 linear containers apply the same per-axis priorities and sibling competition, then use native QBoxLayout stretch, alignment and size policies to allocate space. Static controls keep their preferred size; only siblings with the highest main-axis priority expand. When none expand, children pack at the start rather than stretching or spreading apart. HBox centers compact children vertically; VBox left-aligns them. Native size hints, minimum sizes, fonts and themes still determine exact dimensions. Explicit .qt size-policy overrides remain available, and wrapped native widgets retain their original policy as the priority baseline. See the alignment matrix.
Responsive declarations choose effective settings before the backend applies this sizing
policy. wideLayout/wideStyle and their Textual variants override
ordinary settings when the parent content width reaches a threshold; they do not introduce
another space-allocation algorithm. Declare each method’s breakpoints from small to large; descending thresholds log a warning without changing declaration order. Sibling priorities, weights and cross-axis alignment
continue to follow the rules below.
.visible() sets shared visibility; .wideVisible() overrides it
at a graphical parent-width threshold in logical pixels. .tVisible() and
.tWideVisible() provide Textual boolean overrides and cell-width rules. Textual inherits the shared visibility
boolean unless explicitly overridden, but never inherits pixel bounds. Hidden nodes
collapse their allocated space and freeze child synchronization.
Conditions use the parent's full measured content area, not the remaining space after siblings. A native layout measurement updates State, which causes subscribed declarations to be rebuilt; identical sizes do not notify. Content-dependent parent sizing can still feed back into a breakpoint, so an externally sized parent is preferable. No arbitrary size cap is added, and adaptive layouts do not guarantee that all content fits extremely small areas.
See the Responsive / Adaptive Layout guide for API choices, declaration ordering, terminal units and examples.
Grid computes expansion independently for columns (X) and rows (Y). Each track uses the highest effective priority among its visible cells, including inherited descendant demand. A spanning cell contributes to every track it covers. After accounting for content sizes, only tracks at the highest nonzero priority on that axis receive extra space. If all priorities are zero, tracks remain compact and pack at the left or top. For a Label / Label / TextField form, the first two columns fit their content and the editor column expands.
Equal-priority tracks with equal weights do not imply equal content sizes. On Web/Pyodide, these tracks keep their individual intrinsic sizes and share only the extra space equally. A content-sized nested Grid competing with an outer Spacer therefore keeps short button columns compact, including when another cell spans several columns.
A wide toolbar or nested section spanning both compact and expanding columns must satisfy its additional width through the expanding columns. It must not widen the form's label columns merely because it shares their Grid.
A Grid child's positive weight gives priority 5 on both axes; weight=0 keeps its demand at zero. A track shared by multiple cells takes their maximum priority and, among cells at that priority, their maximum weight (1 for unweighted demand). Adding more rows does not multiply a column's weight. Hidden cells do not contribute; visibility, placement, span and descendant changes recompute the track allocation. Children still fill their assigned cells, subject to native limits, and declared dimensions remain size requirements.
Web/Pyodide Grid labels keep filling their cells, with their text vertically centred and horizontally left-aligned. This aligns ordinary label/input rows without changing track allocation; multiline labels and row spans centre their text within the full assigned cell.
This policy applies to both explicit coordinates and automatic columns on
PySide6, wx, Tkinter, Web, Pyodide and Textual. .columns(n) controls
placement; it does not force equal-width or expanding columns. Font metrics,
padding, minimum sizes and native stretch rounding can still differ by backend.
Flet does not implement Grid. Run python -m PUI.examples.grid_sizing BACKEND
for a three-column form with a spanning toolbar and a nested Grid beside a Spacer.
Grid children use .wideGrid() / .tWideGrid() to override
base positions and spans at inclusive parent-width thresholds. Automatic Grid columns
default to expandChildren=True: after placement, children expand right then down
into empty cells within the existing grid bounds. wideColumns/tWideColumns can
override this setting at a breakpoint; omitting it preserves the current value. Rules merge in
call order without changing vnode identity. Automatic columns use effective spans
but ignore explicit row/column; see Grid reference.
Tkinter converts explicit pixel dimensions to native character/line counts for text controls, measuring the current font/theme and native insets. Requests round up to whole native units, so the requested size can exceed the pixel value by less than one character or line (subject to the native minimum). Font and theme updates recalculate the conversion; removing an override restores the original native request. Canvas and Frame dimensions remain pixels. Axes without a native sizing option, such as Entry height, remain theme-controlled.
HBox should approximately center compact children vertically (middle), and VBox should left-align them horizontally. Children that expand on that axis can still fill the available space. This positions the widget, not the text inside it, and does not require pixel-identical output across toolkits.
Backend support and native limits are listed in the reference alignment matrix. Textual uses native group alignment, so mixed-size children do not necessarily have individual matching center lines. Explicit dimensions also retain backend-specific size-hint/minimum behavior.