Skip to content

Epic: Alternative Interface Renderers (Swift, Kotlin, React) #4

@mikewolfd

Description

@mikewolfd

Motivation

Formspec's core engine runs in TypeScript/WASM. The web component (<formspec-render>) is one rendering surface, but real-world apps need native and framework-specific renderers. The "Alternative Interface Renderers" initiative creates three such surfaces — iOS/macOS (SwiftUI), Android (Jetpack Compose), and React — so apps can consume formspec definitions without the web component.

Architecture Overview

All three renderers share the same three-layer architecture pattern:

  1. Bridge — Connects to formspec-engine (WASM). Swift and Kotlin use a hidden WebView loading a shared HTML bundle with esbuild'd JS + inlined WASM, communicating via typed JSON messages. React imports formspec-engine directly and bridges signals via useSyncExternalStore.
  2. State — Reactive state layer native to each platform. Swift uses @Observable, Kotlin uses Compose State/StateFlow, React uses hooks (useField, useForm, etc.).
  3. Renderer — Component map pattern: a default set of native UI components that render the LayoutNode tree, overridable by the consumer for "bring your own components."

The shared HTML bundle and EngineCommand/EngineEvent message protocol should be extracted to packages/formspec-bridge/ so Swift and Kotlin reference a single source of truth.

Sub-Tasks

Key Shared Artifacts

Artifact Location Consumers
HTML bridge bundle packages/formspec-bridge/ (to be extracted) Swift, Kotlin
EngineCommand/EngineEvent protocol Shared JSON message shapes Swift, Kotlin
formspec-engine WASM packages/formspec-engine/ All three (React direct, Swift/Kotlin via WebView)
Component map pattern Per-renderer All three

Acceptance Criteria

  • All three renderers can load a formspec definition and render a functional form
  • Each renderer has its own test suite (unit + integration)
  • Swift and Kotlin share the same HTML bridge bundle
  • React hooks provide full engine access without the web component
  • Component maps are overridable in all three renderers
  • Tailwind adapter validates the behavior/adapter split works for utility-first CSS frameworks

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions