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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions