Server-driven UI

Judo's JudoAsyncView allows you to render Judo files from a remote server instead of bundled with the app. While this will require an active internet connection on the device at runtime to work, this is useful for when you want to update frequently update elements of your app's UI without having to release a new version of your app.

This strategy is often referred to as "Server-driven UI". Read more here about this emerging technique and its applications.


JudoAsyncView is a SwiftUI view that allows you to render Judo files from a remote server. It's API is modelled somewhat after AsyncImage in SwiftUI.

For example, you can display a JudoView that’s stored on a server:

JudoAsyncView(url: URL(string: ""))

Until the Judo document loads, the view displays a standard placeholder that fills the available space. After the load completes successfully, the view updates to display the Judo document.

Be mindful of incompatible changes

When you use the SDK's API to render Judo components, specify properties, handle custom actions, you are establishing an interface contract between the Judo UI file and your app. This becomes particularly important if you are updating them indepdently.

Therefore, when using JudoAsyncView, be aware that changes to the Judo file on the server may cause incompatibilities with the app if the app is not updated to handle the changes.

Custom Placeholders

You can specify a custom async placeholder using init(url:content:placeholder:). With this initializer, you can also use the content parameter to manipulate the loaded view. For example, you could add a padding or opacity modifier:

JudoAsyncView(url: URL(string: "")) { judoView in
} placeholder: {

For this example, a ProgressView is displayed first, and then the JudoView with the padding and opacity applied.

To gain more control over the loading process, use the init(url:content:) initializer, which takes a content closure that receives an JudoAsyncViewPhase to indicate the state of the loading operation. Return a view that’s appropriate for the current phase:

AsyncJudoView(url: URL(string: "")) { phase in
    if let judoView = phase.judoView {
        judoView // Displays the loaded Judo view.
    } else if phase.error != nil { // Indicates an error.
    } else { // Acts as a placeholder.
Injecting a Custom SwiftUI View