Live editor for the Server-driven UI pattern. JSON spec on the left, rendered widgets on the right. 12 widget types, vanilla JS interpreter, no framework.
From the Thoughtworks Technology Radar Vol 34 (Trial, April 2026).
Live demo: https://sen.ltd/portfolio/server-driven-ui/
- 12 widget types:
vstack,hstack,text,heading,button,card,image,badge,divider,spacer,list,link - Spec validator with per-path error messages (
$.children[1].content — required prop missing) - 4 preset specs: promo card, feed list, pricing tile, empty state
- Live metrics: node count + max depth
- Built-in widget reference panel generated from the same catalog the validator uses
- 21 unit tests covering spec validation, type errors, children handling, metrics
- Zero dependencies, no framework, no build step
npm run serve
# → http://localhost:8080npm testspec.js ← Spec validator + node/depth metrics + widget catalog (DOM 非依存、21 tests)
render.js ← One renderer per widget type, dispatches on spec.type
presets.js ← 4 種のサンプル spec
app.js ← UI グルー(spec → validate → render、metrics 表示)
spec.js には DOM が登場しない。Node テストで全 widget type のバリデーション分岐を完全検証してから、render.js が「spec.type → HTMLElement」だけを責務として持つ。
WIDGETS カタログが single source of truth:
- バリデータは props 必須性をここから読む
- レンダラは type → 関数 dispatcher で呼び分け
- UI 右下の widget reference パネルも同じ catalog を読んで自動生成
新ウィジェットを追加するときは catalog にエントリ追加 → render.js に dispatcher を 1 つ書く → tests 追記。3 ファイル / 3 修正で完結する。
| Widget | Required | Optional | Children? |
|---|---|---|---|
| vstack / hstack | — | spacing, align | ✓ |
| text | content | style | — |
| heading | content | level | — |
| button | label | variant, action | — |
| card | — | title, variant | ✓ |
| image | url | alt, aspect | — |
| badge | label | tone | — |
| divider | — | — | — |
| spacer | — | size | — |
| list | — | spacing | ✓ |
| link | label, url | — | — |
MIT. See LICENSE.
