Skip to content

Alignment and Distribution

A container places its children along two axes. The justify_children_* utilities distribute them along the main axis (across a row, down a col), and the align_children_* utilities place them on the cross axis. A child can override its parent's cross-axis alignment for itself with align_self_*.

The examples on this page title each panel with this helper, which draws its text over the top border:

def title(content: str) -> Text:
    return Text(content=f" {content} ", style=position_absolute | inset_top(-1) | inset_left(1))

Distributing children along the main axis

The justify_children_* utilities share out the free space a row or column has left over after its children take their sizes. Children that grow leave no free space, so these only matter when nothing claims it.

@component
def justify() -> Div:
    return Div(
        style=col,
        children=[
            Div(
                style=row | justify | border,
                children=[
                    title(name),
                    Text(style=border | border_heavy, content="a"),
                    Text(style=border | border_heavy, content="bb"),
                    Text(style=border | border_heavy, content="ccc"),
                ],
            )
            for name, justify in (
                ("justify_children_start", justify_children_start),
                ("justify_children_center", justify_children_center),
                ("justify_children_end", justify_children_end),
                ("justify_children_space_between", justify_children_space_between),
                ("justify_children_space_around", justify_children_space_around),
                ("justify_children_space_evenly", justify_children_space_evenly),
            )
        ],
    )

The justify_children utilities

┌─ justify_children_start ───────────────────────┐
│┏━┓┏━━┓┏━━━┓                                    │
│┃a┃┃bb┃┃ccc┃                                    │
│┗━┛┗━━┛┗━━━┛                                    │
└────────────────────────────────────────────────┘
┌─ justify_children_center ──────────────────────┐
│                  ┏━┓┏━━┓┏━━━┓                  │
│                  ┃a┃┃bb┃┃ccc┃                  │
│                  ┗━┛┗━━┛┗━━━┛                  │
└────────────────────────────────────────────────┘
┌─ justify_children_end ─────────────────────────┐
│                                    ┏━┓┏━━┓┏━━━┓│
│                                    ┃a┃┃bb┃┃ccc┃│
│                                    ┗━┛┗━━┛┗━━━┛│
└────────────────────────────────────────────────┘
┌─ justify_children_space_between ───────────────┐
│┏━┓                  ┏━━┓                  ┏━━━┓│
│┃a┃                  ┃bb┃                  ┃ccc┃│
│┗━┛                  ┗━━┛                  ┗━━━┛│
└────────────────────────────────────────────────┘
┌─ justify_children_space_around ────────────────┐
│      ┏━┓            ┏━━┓            ┏━━━┓      │
│      ┃a┃            ┃bb┃            ┃ccc┃      │
│      ┗━┛            ┗━━┛            ┗━━━┛      │
└────────────────────────────────────────────────┘
┌─ justify_children_space_evenly ────────────────┐
│         ┏━┓         ┏━━┓         ┏━━━┓         │
│         ┃a┃         ┃bb┃         ┃ccc┃         │
│         ┗━┛         ┗━━┛         ┗━━━┛         │
└────────────────────────────────────────────────┘

Aligning children on the cross axis

The default, align_children_stretch, fills the cross axis; the others keep each child at its content size and place it.

@component
def align() -> Div:
    return Div(
        style=row,
        children=[
            Div(
                style=row | align | fill(1) | border,
                children=[
                    title(name),
                    Text(style=border | border_heavy, content="a"),
                    Text(style=border | border_heavy, content="b\nb"),
                    Text(style=border | border_heavy, content="c\nc\nc"),
                ],
            )
            for name, align in (
                ("align_children_start", align_children_start),
                ("align_children_center", align_children_center),
                ("align_children_end", align_children_end),
                ("align_children_stretch", align_children_stretch),
            )
        ],
    )

The align_children utilities

┌─ align_children_start ─────┐┌─ align_children_center ────┐┌─ align_children_end ───────┐┌─ align_children_stretch ───┐
│┏━┓┏━┓┏━┓                   ││                            ││                            ││┏━┓┏━┓┏━┓                   │
│┃a┃┃b┃┃c┃                   ││      ┏━┓                   ││                            ││┃a┃┃b┃┃c┃                   │
│┗━┛┃b┃┃c┃                   ││┏━┓┏━┓┃c┃                   ││      ┏━┓                   ││┃ ┃┃b┃┃c┃                   │
│   ┗━┛┃c┃                   ││┃a┃┃b┃┃c┃                   ││   ┏━┓┃c┃                   ││┃ ┃┃ ┃┃c┃                   │
│      ┗━┛                   ││┗━┛┃b┃┃c┃                   ││┏━┓┃b┃┃c┃                   ││┃ ┃┃ ┃┃ ┃                   │
│                            ││   ┗━┛┗━┛                   ││┃a┃┃b┃┃c┃                   ││┃ ┃┃ ┃┃ ┃                   │
│                            ││                            ││┗━┛┗━┛┗━┛                   ││┗━┛┗━┛┗━┛                   │
└────────────────────────────┘└────────────────────────────┘└────────────────────────────┘└────────────────────────────┘

Aligning one child

align_self_* on a child replaces its parent's align_children_* for that child alone.

@component
def align_self() -> Div:
    return Div(
        style=row | align_children_start | gap(1) | border,
        children=[
            title("row | align_children_start"),
            Text(style=border | border_heavy, content="no align_self"),
            Text(style=align_self_center | border | border_heavy, content="align_self_center"),
            Text(style=align_self_end | border | border_heavy, content="align_self_end"),
            Text(style=align_self_stretch | border | border_heavy, content="align_self_stretch"),
        ],
    )

The align_self utilities

┌─ row | align_children_start ─────────────────────────────────────────────────┐
│┏━━━━━━━━━━━━━┓                                      ┏━━━━━━━━━━━━━━━━━━┓     │
│┃no align_self┃                                      ┃align_self_stretch┃     │
│┗━━━━━━━━━━━━━┛ ┏━━━━━━━━━━━━━━━━━┓                  ┃                  ┃     │
│                ┃align_self_center┃                  ┃                  ┃     │
│                ┗━━━━━━━━━━━━━━━━━┛ ┏━━━━━━━━━━━━━━┓ ┃                  ┃     │
│                                    ┃align_self_end┃ ┃                  ┃     │
│                                    ┗━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━┛     │
└──────────────────────────────────────────────────────────────────────────────┘

Centering a box

Center a box on both axes with center_children, which is justify_children_center | align_children_center. It works in a grid too: there it centers the grid's tracks, and a grid with no template sizes its one track to fit its lone child. To center a box over other content rather than among it, see A dialog centered over the app.

@component
def center() -> Div:
    return Div(
        style=row,
        children=[
            Div(
                style=row | center_children | fill(1) | border,
                children=[title("flexbox"), Text(style=border | border_heavy, content="centered")],
            ),
            Div(
                style=display_grid | center_children | fill(1) | border,
                children=[title("grid"), Text(style=border | border_heavy, content="centered")],
            ),
        ],
    )

Centering with flexbox and grid

┌─ flexbox ─────────────┐┌─ grid ────────────────┐
│                       ││                       │
│                       ││                       │
│       ┏━━━━━━━━┓      ││       ┏━━━━━━━━┓      │
│       ┃centered┃      ││       ┃centered┃      │
│       ┗━━━━━━━━┛      ││       ┗━━━━━━━━┛      │
│                       ││                       │
│                       ││                       │
└───────────────────────┘└───────────────────────┘

Content larger than its container

The *_center and *_end utilities are CSS's safe alignments: content too large for its container starts at the container's start edge and overflows only past the end, so its beginning stays on screen. Each has an *_unsafe counterpart with CSS's default behavior, which centers or end-aligns the content anyway and overflows past the start edge too.

@component
def overflow() -> Div:
    return Div(
        style=row | pad_y(4),
        children=[
            Div(
                style=col | justify | fill(1) | border,
                children=[title(name), Text(content=TALL)],
            )
            for name, justify in (
                ("justify_children_center", justify_children_center),
                ("justify_children_center_unsafe", justify_children_center_unsafe),
            )
        ],
    )

Safe and unsafe centering of content taller than its container

                                    line 1                            
┌─ justify_children_center ───────┐┌line 2                           ┐
│line 1                           ││line 3                           │
│line 2                           ││line 4                           │
│line 3                           ││line 5                           │
│line 4                           ││line 6                           │
│line 5                           ││line 7                           │
│line 6                           ││line 8                           │
│line 7                           ││line 9                           │
└line 8                           ┘└line 10                          ┘
 line 9                             line 11                           
 line 10                            line 12                           
 line 11                                                              
 line 12