VStack#

A container that stacks children top-to-bottom using the pack geometry manager. Use gap= for even spacing, fill_items='x' to stretch children to the full width, and fill='both', expand=True to let the stack grow with the window.

VStack — light theme VStack — dark theme

Usage#

Gap#

gap= sets uniform spacing in pixels between children.

# gap=4 - items close together
with bs.VStack(gap=4, show_border=True, padding=8):
    for i in range(1, 5):
        bs.Button(f"Item {i}")

# gap=16 - items spread apart
with bs.VStack(gap=16, show_border=True, padding=8):
    for i in range(1, 5):
        bs.Button(f"Item {i}")
VStack gap — light theme VStack gap — dark theme

Child fill#

fill_items='x' stretches every child to the full container width. Individual children can override this with their own fill=.

with bs.VStack(gap=8, fill_items="x"):
    bs.TextField()          # fills horizontally by default
    bs.Button("Submit", accent="primary")
VStack fill — light theme VStack fill — dark theme

Child alignment#

anchor_items= controls horizontal alignment of children that do not fill the full width. Use 'w' (left), 'center', or 'e' (right).

with bs.VStack(gap=8, anchor_items="w",      show_border=True, padding=8, width=180, height=120):
    bs.Button("A"); bs.Button("B")

with bs.VStack(gap=8, anchor_items="center", show_border=True, padding=8, width=180, height=120):
    bs.Button("A"); bs.Button("B")

with bs.VStack(gap=8, anchor_items="e",      show_border=True, padding=8, width=180, height=120):
    bs.Button("A"); bs.Button("B")
VStack alignment — light theme VStack alignment — dark theme

Fixed height#

Note

height= and width= fix the container size and prevent children from resizing it. Setting both is the simplest path — the frame is fully constrained and works without any extra kwargs:

with bs.VStack(height=200, width=300, show_border=True):
    bs.Button("Fully fixed")

When only one dimension is set, the other axis collapses to zero. Add fill= and expand= to let the parent control the open axis:

# height only — width comes from parent
with bs.VStack(height=120, fill="x", gap=8):
    bs.Button("Fixed height, fills parent width")
with bs.VStack(height=120, gap=8, anchor_items="center"):
    bs.Label("Fixed 120 px tall, fills parent width")

Background#

surface= sets the container background. It accepts a surface token ('content', 'card', 'chrome', 'overlay') or any accent token ('primary', 'success', etc.) with optional modifiers:

with bs.VStack(surface="card", padding=12, gap=8):
    bs.Label("Sits on card surface")

with bs.VStack(surface="primary[subtle]", padding=12, gap=8):
    bs.Label("Accent-tinted background")

Border#

show_border=True draws a 1 px border along the inside edge of the frame. Without padding, children render flush against it. Use at least padding=1 to give the border visual clearance.

with bs.VStack(gap=8, show_border=True, padding=8):
    bs.Label("Bordered section")
    bs.Button("Action")
VStack border — light theme VStack border — dark theme

Self-placement#

fill=, expand=, and anchor= control how the VStack itself is placed within its parent — separate from how it arranges its own children.

# Fill the parent and grow with the window
with bs.VStack(fill="both", expand=True, gap=8):
    bs.Label("Grows with window")

Widget sizing#

All widgets accept self-placement kwargs via **kwargs. The parent container determines which options apply — stack-based parents use stack kwargs, grid-based parents use grid kwargs. Unrecognised keys are silently ignored.

Stack#

Used inside VStack, HStack, App, and other stack containers.

fill

Fill direction: 'x', 'y', 'both', or 'none'.

expand

Grow to consume extra space in the parent. True or False.

anchor

Alignment when the widget does not fill the available slot: 'n', 's', 'e', 'w', 'center', 'nw', etc.

margin

External spacing in pixels. Accepts an integer (equal on all sides), a 2-tuple (horizontal, vertical), or a 4-tuple (left, top, right, bottom).

margin_x

Horizontal external spacing (left and right). Accepts an integer or a 2-tuple (left, right) for asymmetric spacing. Overrides the horizontal component of margin=.

margin_y

Vertical external spacing (top and bottom). Accepts an integer or a 2-tuple (top, bottom) for asymmetric spacing. Overrides the vertical component of margin=.

Grid#

Used inside a Grid container.

row / column

Zero-based row and column indices.

rowspan / columnspan

Number of rows or columns to span.

sticky

Alignment and fill within the grid cell. Any combination of 'n', 's', 'e', 'w' — e.g. 'ew' stretches horizontally, 'nsew' fills the entire cell.

margin

External spacing in pixels. Accepts an integer, a 2-tuple (horizontal, vertical), or a 4-tuple (left, top, right, bottom).

margin_x

Horizontal external spacing. Accepts an integer or (left, right).

margin_y

Vertical external spacing. Accepts an integer or (top, bottom).

See also#

HStack — horizontal equivalent. Grid — row and column layout. Card and GroupBox — VStack with an elevated background or labelled border.

API#

The complete reference for VStack lives on the Widgets API page. At a glance:

VStack

Vertical stack — lays out children top-to-bottom with optional gap and alignment.

Full Example#

 1
 2with bs.App(title="VStack Demo", size=(680, 780), padding=20, gap=16) as app:
 3
 4    # Gap
 5    bs.Label("gap", font="heading-sm")
 6    with bs.Grid(columns=[1, 1], gap=(16, 0), fill="x", sticky_items="new"):
 7        with bs.VStack(gap=4, fill="x"):
 8            bs.Label("gap=8", font="caption")
 9            with bs.VStack(show_border=True, gap=8, padding=8, fill="x", fill_items="x"):
10                for lbl in ("A", "B", "C"):
11                    bs.Button(lbl)
12        with bs.VStack(gap=4, fill="x"):
13            bs.Label("gap=16", font="caption")
14            with bs.VStack(show_border=True, gap=16, padding=8, fill="x", fill_items="x"):
15                for lbl in ("A", "B", "C"):
16                    bs.Button(lbl)
17
18    # anchor_items
19    bs.Label("anchor_items", font="heading-sm")
20    with bs.Grid(columns=[1, 1, 1], gap=(16, 0), fill="x", sticky_items="new"):
21        with bs.VStack(gap=4, fill="x"):
22            bs.Label("anchor='w'", font="caption")
23            with bs.VStack(padding=8, show_border=True, height=100, fill="x"):
24                bs.Button("anchor='w'", anchor="w", expand=True)
25        with bs.VStack(gap=4, fill="x"):
26            bs.Label("anchor='center'", font="caption")
27            with bs.VStack(padding=8, show_border=True, height=100, fill="x"):
28                bs.Button("anchor='center'", anchor="center", expand=True)
29        with bs.VStack(gap=4, fill="x"):
30            bs.Label("anchor='e'", font="caption")
31            with bs.VStack(padding=8, show_border=True, height=100, fill="x"):
32                bs.Button("anchor='e'", anchor="e", expand=True)
33
34    # expand and fill
35    bs.Label("expand and fill", font="heading-sm")
36    with bs.Grid(columns=[1, 1, 1], gap=(16, 0), fill="x", sticky_items="new"):
37        with bs.VStack(gap=4, fill="x"):
38            bs.Label("Neither", font="caption")
39            with bs.VStack(show_border=True, padding=8, height=180, fill="x", gap=6, fill_items="x"):
40                bs.Button("Header")
41                bs.Button("Content")
42                bs.Button("Footer")
43        with bs.VStack(gap=4, fill="x"):
44            bs.Label("expand=True only", font="caption")
45            with bs.VStack(show_border=True, padding=8, height=180, fill="x", gap=6, fill_items="x"):
46                bs.Button("Header")
47                bs.Button("Content", expand=True)
48                bs.Button("Footer")
49        with bs.VStack(gap=4, fill="x"):
50            bs.Label("fill='y', expand=True", font="caption")
51            with bs.VStack(show_border=True, padding=8, height=180, fill="x", gap=6, fill_items="x"):
52                bs.Button("Header")
53                bs.Button("Content", fill="y", expand=True)
54                bs.Button("Footer")
55
56app.run()