Pages, sections and widgets
The JSON envelope every Flow-UI response follows, from the page down to a single widget, and how it maps onto native SwiftUI views.
Every response is one shape: a page holds sections, sections hold widgets. Learn this envelope once and every Flow-UI payload becomes readable.
The page#
header and footer are widget strips. When sticky is true they pin outside the scrolling area, which is how persistent filter rails and cart bars work. When false they scroll with the content.
Sections#
A section owns an arrangement and spacing for its widgets:
verticalstacks widgets top to bottom.carouselscrolls horizontally with view aligned snapping. A widget'slayout.widthfraction produces peeking cards.gridlays widgets incolumnsflexible columns.
A section's optional header widget pins while its section scrolls beneath it, the classic sticky section title.
Unknown arrangement strings fall back to vertical, so backends can invent new arrangements without breaking old clients.
Widgets#
Five envelope fields are uniform across every widget:
typeselects the registered SwiftUI view.idgives the widget stable identity for state and mutations. Send one whenever a widget is interactive or replaceable.layoutis the backend controlled chrome, covered in Layout.actionsmaps event names to declarative actions, covered in Actions.trackingis opaque JSON your analytics receives untouched.
The data payload belongs to the widget type. The framework never looks inside it; the registered widget decodes it into its own typed model.
Pagination#
When pagination.has_more is true, Flow-UI renders a sentinel after the last section. When it appears, the store requests the next page and echoes postback exactly as received. New sections append; existing widget state is untouched.