Joy DOM

How it works

The pipeline that turns a Joy DOM document into native SwiftUI — layout powered by the flexbox-swift engine.

JoyDom turns a Joy DOM JSON document into a live SwiftUI view tree in four stages. It owns decode, cascade, and render; the layout stage is delegated to flexbox-swift, a Swift flexbox engine, so flex behavior matches the web spec rather than being re-approximated in SwiftUI.

Joy DOM JSON

JoyDom

FlexBox

SwiftUI

decode + cascade

compute layout

render

box styles

frames

native views

The four stages

  1. DecodeSpec is Codable, so the JSON document decodes straight into the model: a tree of Nodes plus the style record and breakpoints.
  2. Cascade — selectors (div, .class, #id) and the active breakpoint resolve against the Viewport into one fully-computed style per node — exactly the CSS cascade, applied ahead of layout.
  3. Layout — each node's box style (display, flexDirection, gap, padding, sizing, …) is handed to FlexBox (flexbox-swift), which computes the frame for every node, the same way a browser's flexbox engine would.
  4. RenderJoyDom walks the laid-out tree and emits native views: flex containers through a FlexLayout container, text through SwiftUI Text, img through AsyncImage, and your custom components wherever their type appears.

Powered by flexbox-swift

The layout engine

Layout is delegated to j0yhq/flexbox-swift — a standalone Swift flexbox implementation exposed as the FlexLayout product. Keeping a real flexbox engine in the pipeline (rather than mapping CSS onto SwiftUI's stacks) is what lets the Swift renderer match the web and Kotlin renderers pixel-for-pixel on the shared conformance fixtures.

Because the engine owns layout, the styles you write in a document behave like CSS flexbox: flex-grow/flex-shrink/flex-basis, align-items/justify-content, wrapping, gaps, and the box model all resolve the same as they do in the React renderer.

Quick showcase

To see the whole pipeline end to end, run JoyDOMShowcase — one self-contained file, cross-platform (iOS + macOS), no images or external state. It renders an inline JSON card with the built-in primitives plus a single custom badge component, and a lone .onEvent handler increments a like count, re-decoding the document on each tap.

It ships as a runnable example in the public package, so you can clone and run it directly — swift run builds the macOS app and pulls the JoyDOM binary automatically:

git clone https://github.com/j0yhq/joydom-swift.git
cd joydom-swift/Example
swift run JoyDOMShowcase

iOS / requirements

Needs Xcode 16+ (Swift 5.9+), macOS 13+ or iOS 16+. swift run launches the macOS app; to run on iOS instead, open Example/Package.swift in Xcode and run the JoyDOMShowcase scheme on a simulator. To wire JoyDom into your own app from scratch, see Getting started.

JoyDOMShowcase is deliberately minimal; the joy-dom monorepo additionally has a richer Native-vs-Web-vs-Kotlin conformance demo (JoyDomDemo) for contributors.

Where next

On this page