Skip to content

0xWDG/DynamicUI

Repository files navigation

DynamicUI

Create SwiftUI interfaces from JSON component trees. DynamicUI supports nested layouts, interactive controls, runtime value updates, conditional strings, and a focused set of SwiftUI modifiers.

Swift Package Manager License

Requirements

  • Swift 5.9+ (Xcode 15+)
  • iOS 15+, macOS 12+, tvOS 14+, watchOS 8+, macCatalyst 15+, visionOS 1.0+

Installation

Add DynamicUI using Swift Package Manager:

dependencies: [
    .package(url: "https://github.com/0xWDG/DynamicUI.git", branch: "main"),
],
targets: [
    .target(name: "MyTarget", dependencies: [
        .product(name: "DynamicUI", package: "DynamicUI"),
    ]),
]

And import it:

import DynamicUI

Usage

import SwiftUI
import DynamicUI

struct ContentView: View {
    let json = """
    [
        {
            "type": "Text",
            "title": "Wait, am i generating views from JSON?",
            "modifiers": {"foregroundStyle":"red","opacity":0.6}
        },
        {
            "type": "Button",
            "title": "Click me",
            "eventHandler": "customHandler"
        },
        {
            "type": "Toggle",
            "title": "Toggle me",
            "identifier": "my.toggle.1"
        }
    ]
    """

    @State private var component: DynamicUIComponent?
    @State private var error: Error?

    var body: some View {
        DynamicUI(
            json: json,
            component: $component,
            error: $error
        )
    }
}

Conditional expressions can select a string value using another component's current state:

[
    {
        "type": "Toggle",
        "title": "Toggle me",
        "identifier": "myIdentifier"
    },
    {
        "type": "Label",
        "title": "Shine",
        "url": "{$myIdentifier ? star.fill : star}"
    }
]

The syntax is {$identifier ? valueWhenTrue : valueWhenFalse}. It works in string-valued component fields, including title, text, url, modifiers, and parameters.

Handle interactions

The component binding receives the latest interacted-with component. Stateful controls include their new value in state; identifier and eventHandler let your application route the update.

.onChange(of: component) { component in
    guard let component else { return }

    print(component.identifier as Any)
    print(component.eventHandler as Any)
    print(component.state as Any)
}

You can use a callback instead of a binding:

import SwiftUI
import DynamicUI

struct ContentView: View {
    let json = """
    [
        {
            "type": "Text",
            "title": "Wait, am i generating views from JSON?",
            "modifiers": {"foregroundStyle":"red","opacity":0.6}
        },
        {
            "type": "Button",
            "title": "Click me",
            "eventHandler": "customHandler"
        },
        {
            "type": "Toggle",
            "title": "Toggle me",
            "identifier": "my.toggle.1"
        }
    ]
    """

    @State private var error: Error?

    var body: some View {
        DynamicUI(
            json: json,
            callback: { component in
                // This contains everything passed as a component (type, title, identifier, ...)
                print(component)
            },
            error: $error
        )
    }
}

JSON schema

Every component requires a case-sensitive type. Common optional fields are:

Field Purpose
title Label, title, placeholder, or accessibility label
identifier Stable key for updates and conditional expressions
eventHandler Application-defined event name returned on interaction
defaultValue Initial value for stateful controls
children Nested component array for containers
url SF Symbol name for images, labels, and tab labels
disabled Disables the component
modifiers Visual and behavioral modifiers
minimumValue, maximumValue Numeric bounds for sliders and progress views

Unknown component types render no view. Decode failures are written to the optional error binding and display a fallback error view.

Playground application

The Playground directory contains an Xcode project with basic and exhaustive JSON examples. It is available for macOS, iOS, watchOS, tvOS, and visionOS.

Supported SwiftUI views

DynamicUI supports content views, controls, layouts, containers, navigation, tabs, and split views. See the complete schema, platform behavior, component examples, and modifier reference in the documentation.

Images

Playground

image image

Used By

Contact

πŸ¦‹ @0xWDG 🐘 mastodon.social/@0xWDG 🐦 @0xWDG 🧡 @0xWDG 🌐 wesleydegroot.nl πŸ€– Discord

About

Create a SwiftUI user interface through a JSON file. The JSON file will contain the structure of the user interface, and the program will create the user interface based on the JSON file.

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors