# Picking a Swift HTML DSL in 2026

> Why this site renders HTML with Elementary and swift-markdown instead of Plot, Ink, or Ignite.

2026-09-12 · cooperlabs-dev

This site is Hummingbird 2 serving Markdown files. I wanted the same server to answer terminal clients and `Accept: text/markdown` with the Markdown itself, so I needed a runtime renderer. A static generator was out.

Plot is the popular answer and has the stars. Its last release was May 2023. I already use it on kalebcooper.com, and it crashed production there once. `.if(condition, node)` builds the node eagerly, so a force-unwrap inside it ran even when the condition was false. The fix was `.unwrap`. So it's frozen and it's easy to hold wrong.

Ink is from the same author and last shipped in April 2023. Same problem. I used Apple's swift-markdown instead, which gives me a real AST.

Ignite came up too, but it's a static site generator. Serving its output from a Railway container means paying for a server whose only job is a file middleware, and it still can't negotiate content at runtime.

Elementary is a runtime HTML DSL built for server-side Swift, with streaming render. I'm on 0.8.1 with HummingbirdElementary 0.5.1. It's pre-1.0, so both are pinned `.upToNextMinor(from:)` because a 0.x minor bump is breaking. One gotcha: hummingbird-elementary declares `elementary-swift/elementary`, and SwiftPM rejects two URLs for one identity. The old `sliemeobn` URL can't sit next to it.

In practice page builders are pure functions returning `some HTML`. A `Layout` struct conforms to `HTMLDocument` and owns the head, header, and footer.

```swift
static func render(entry: Entry, env: Env) -> some HTML {
    Layout(title: entry.title, description: entry.summary, path: entry.path, env: env) {
        article(.class("prose")) { h1 { entry.title } }
    }
}
```

Elementary already had every tag the site needed. The downsides I actually hit are pre-1.0 churn risk, a small community, and fewer examples than Plot to crib from.

Went with Elementary plus swift-markdown. The site is live on it.
