Skip to content
Flow-UILive

Quick start

Build your first server driven UI screen in SwiftUI: register widgets, implement a page loader, and render backend JSON as native iOS views.

Three pieces connect Flow-UI to your app: a widget registry, a page loader, and a page view. This page wires all three.

1. Register widgets#

Create one registry at startup and tell it which widgets exist. The starter library covers the everyday shapes; your own widgets register the same way.

AppBootstrap.swiftswift
import FlowUI
 
let registry = WidgetRegistry()
FlowWidgets.register(on: registry)      // the starter library
registry.register(OrderCardWidget.self) // your own widgets

2. Implement a loader#

Flow-UI ships no HTTP stack on purpose. Implement PageLoader with whatever client you already have and return raw response bytes; Flow-UI does the decoding.

APILoader.swiftswift
struct APILoader: PageLoader {
    func loadPage(_ request: PageRequest) async throws -> Data {
        switch request.kind {
        case .initial, .refresh:
            return try await client.get("/pages/\(request.pageID)")
        case .nextPage(let postback):
            return try await client.post("/pages/\(request.pageID)/next", body: postback)
        case .action(let payload):
            return try await client.post("/actions", body: payload)
        }
    }
}

The postback in pagination is opaque: whatever your backend sent in the previous response comes back untouched, so cursors can be any shape you like.

3. Render the page#

PageStore owns loading, refresh, pagination and mutations. FlowPageView renders whatever the store holds, including the shimmer skeleton, error and empty states.

HomeScreen.swiftswift
struct HomeScreen: View {
    @State private var store = PageStore(
        pageID: "home",
        loader: APILoader(),
        registry: registry
    )
 
    var body: some View {
        FlowPageView(store: store)
    }
}

UIKit apps embed the same thing in one line with FlowHostingController(store:).

What you get out of the box#

  • Pull to refresh when the response asks for it.
  • Cursor pagination through a sentinel at the end of the list.
  • A shimmering skeleton while loading, an error state with retry, and an empty state.
  • Bottom sheets, toasts and page mutations driven entirely by action JSON.