type: "custom", the React Native and Flutter SDKs call your customScreenBuilder.
On SDKs that expose customScreenBuilder, the builder receives a context object with:
ctx.formData: the data already collected in the flowctx.screenData: the JSON for the current custom screenctx.onNext(): move to the next screenctx.onPrevious(): move to the previous screenctx.onFinish(): end the flowctx.onJumpTo(screenId): jump to another screen in the same flow
Basic flow shape
In Flowboard, the screen itself stays part of the same flow. You only replace the rendering for that one step.Simple example
Start with oneif and one custom screen. This is the easiest way to understand the lifecycle.
The Swift package now exposes
customScreenBuilder in FlowboardLaunchOptions — pass a @MainActor (FlowboardContext) -> UIViewController closure to replace a type: "custom" screen natively, exactly like the React Native and Flutter examples. The onCustomAction example above remains useful when you want to present a native surface from a button action instead of replacing a screen.Recommended production setup
For production, keep yourcustomScreenBuilder small and route by screen ID in one place.
This gives you a single entry point, keeps launch code clean, and makes each custom screen easier to test.
Recommended structure:
- Put the router in one dedicated file
- Use a
switchonscreenId - Load each custom screen from its own file
- Keep a fallback screen for unknown IDs
Adjust the example file paths to match your app structure. The important part is the separation between the router and the screen components. On native iOS, keep the same router idea, but route to your own presented UIKit or SwiftUI surfaces from
onCustomAction(...).Practical guidance
Use custom screens for cases like:- A native paywall tied to your purchase SDK
- A login or signup screen backed by your own auth flow
- A profile summary or confirmation step based on earlier answers
- A screen that depends on native features not exposed by standard Flowboard components