<- Back to Complex Components

Purpose

FlexContainer is a direction-agnostic fill container. It tells each client to let the container grow into the available space without adding row or column semantics of its own.

Use it when child content must remain responsive to the space around it:

  • with no children, it acts as a spacer between siblings
  • with children, it acts as a growing wrapper for a child layout or data component
  • inside a page shell, it fills the remaining body or sidebar space

FlexContainer does not define direction, wrapping, alignment, or spacing. Put Row, Column, List, Grid, or another layout component inside it when the children need those rules.

Constructor

FlexContainer(
    id: str,
    children: list[str | Component] | None = None,
)

Properties

Property Type Default Description
children list[str | Component] [] Child components rendered inside the fill area. Empty children make the container behave as a spacer.
style str | dict none Common style property. Useful for preview frames, padding, and borders.
visible bool true Common runtime visibility property.

Store-Bound Card Children

The demo uses FlexContainer as the fill wrapper and renders six Card components as first-level children. Each card keeps a fixed width and reads its title, body, and badge from page store.

for index, (title, text, badge) in enumerate(card_values):
    builder.set_store(f"/components_test/flex/cards/{index}/title", title, scope="page")
    builder.set_store(f"/components_test/flex/cards/{index}/text", text, scope="page")
    builder.set_store(f"/components_test/flex/cards/{index}/badge", badge, scope="page")

card = sdk.ui.Card(
    "flex_card_0",
    [
        sdk.ui.Title(
            "flex_card_0_title",
            bound.store("/components_test/flex/cards/0/title", scope="page", default="Intake"),
            level=3,
        ),
        sdk.ui.Text(
            "flex_card_0_text",
            bound.store("/components_test/flex/cards/0/text", scope="page", default="Direct child card fed by page store."),
        ),
        sdk.ui.Badge(
            "flex_card_0_badge",
            bound.store("/components_test/flex/cards/0/badge", scope="page", default="Store"),
            variant="info",
        ),
    ],
    variant="default",
)
card.set_property("style", "width: 240px; min-width: 240px;")

wrapper = sdk.ui.FlexContainer("card_wrapper", ["flex_card_0", "flex_card_1", "flex_card_2", "flex_card_3", "flex_card_4", "flex_card_5"])
wrapper.allow("style.set", "children.append", "children.set")

Spacer Example

An empty FlexContainer grows between siblings. In a Row, this pushes the following item to the opposite side.

spacer = sdk.ui.FlexContainer("toolbar_spacer")
row = sdk.ui.Row("toolbar", ["left_action", spacer.id, "right_action"])

Bindings and Updates

children is the main structural surface. Use direct child components when the container should only provide a fill area; use a child List, Grid, Row, or Column when the child layout needs its own rendering rules. Common properties such as style, visible, show_if, hide_if, and required_permissions work like other components.

store_wrapper = sdk.ui.FlexContainer("store_wrapper", ["flex_card_0", "flex_card_1"])
store_wrapper.set_property(
    "style",
    bound.store("/components_test/flex/panel_style", scope="page", default="padding: 12px;"),
)

data_wrapper = sdk.ui.FlexContainer("data_wrapper", ["data_text"])
data_wrapper.set_property(
    "style",
    bound.data("/components_test/flex_model/panel_style", default="padding: 12px;"),
)

live_wrapper = sdk.ui.FlexContainer("live_wrapper", ["live_text"])
live_wrapper.allow("children.append")

Runtime updates:

surface_id = ctx["_surface_id"]

sdk.effects.ui_messages([
    {
        "stateUpdate": {
            "scope": "page",
            "values": {
                "/components_test/flex/cards/0/title": "Plan",
                "/components_test/flex/cards/0/text": "Updated through page store.",
                "/components_test/flex/cards/0/badge": "Updated",
                "/components_test/flex/panel_style": "padding: 12px; border: 1px solid #4f7cff;",
            },
        }
    }
])

sdk.ui.Builder.build_data_model_update_payload(
    surface_id=surface_id,
    data={"components_test": {"flex_model": {"panel_style": "padding: 12px;"}}},
)

sdk.effects.ui_collection_append(
    "live_wrapper",
    "children",
    sdk.ui.Text("new_child", "Added child").to_dict(),
    surface_id=surface_id,
)

Visibility and Permissions

wrapper.set_show_if({
    "conditions": [
        {
            "left": bound.store("/components_test/flex/show", scope="page", default=True),
            "op": "==",
            "right": True,
        }
    ]
})
wrapper.set_hide_if({
    "conditions": [
        {
            "left": bound.store("/components_test/flex/hide", scope="page", default=False),
            "op": "==",
            "right": True,
        }
    ]
})
wrapper.set_required_permissions(["components.layout.view"])