A declarative, reactive UI toolkit for Scala Native that
renders with Cairo on top of
SDL3. suit pairs the host-agnostic
vdom core — a React-shaped reconciler and hooks —
with a Flutter-style constraint-layout engine and a retained render tree. Write
components with useState, lay them out with col / row / box / text, and let state
drive the screen. In short: Flutter in Scala Native.
Status: published to Maven Central, but pre-1.0 and evolving — pin a version and expect the occasional breaking change. Add
"io.github.edadma" %%% "suit" % "0.0.12"to a Scala Native project, or build from the checkout to contribute (see Documentation).
Full documentation — getting started, the three-tree architecture, the constraint-layout
model, the input system, and the DSL and widget reference — is at
suit.edadma.dev (source in docs/). This README is
a quick taste; the site is the reference.
suit is one layer of a three-layer system, the same split Flutter draws between its widgets, elements, and render objects:
| Layer | What it is | Provided by |
|---|---|---|
| VNodes / widgets | what you write: col(...)(box(...), text()) |
vdom |
| Elements | the reconciled, stateful instance tree | vdom |
| RenderObjects | layout, paint, hit-test | suit |
vdom is host-agnostic — the same core drives the browser DOM in riposte and the screen here. suit supplies only the rendering layer underneath — drawn with Cairo, presented through SDL3.
The model Flutter and SwiftUI both adopted:
Constraints go down, sizes come up, the parent sets positions.
A parent hands each child a range of allowed sizes; the child picks its own size within that range; the parent positions it. One recursive rule — no monolithic solver, no guessing which flex property wins. The whole engine is pure Scala with no SDL dependency, so layout, the render tree, and geometry are unit-tested headlessly on the JVM against a recording canvas.
A small library of controls — all theme-driven and animated, composed from the DSL
primitives: buttons, checkboxes, switches, radio groups, sliders, tabs, progress bars,
badges, dividers, alerts, cards, tooltips, menus, dropdown Selects, right-click context
menus, an application menuBar, modal dialogs, a resizable splitter, and a scrollArea with a visible draggable
scrollbar that scrolls one axis or, with both = true, both at once. Text entry comes in a
single-line TextField and a soft-wrapping multi-line TextArea — both with full editing: clipboard
copy/cut/paste, undo/redo, and word-wise cursor movement and deletion (⌘ on macOS, Ctrl elsewhere).
Large data sets are served by a
virtualized data grid — dataTable over a virtualList that only builds the rows under
the viewport, so a thousand-row result stays smooth, with sortable, resizable columns. See the
widget reference.
For custom drawing there are two escape hatches: canvas hands your routine suit's Canvas
each frame (a chart, a game, a sketch pad), and surface wraps an application-owned image
surface you draw into yourself with the full underlying graphics API (raw Cairo on Native) and
re-blit on demand via a SurfaceHandle — the retained route for content suit's Canvas doesn't
cover. See the DSL reference.
import io.github.edadma.suit.*
import io.github.edadma.suit.dsl.*
import io.github.edadma.suit.widgets.*
val App = view {
val (count, setCount, _) = useState(0)
col(spacing = 16, mainAxisAlignment = MainAxisAlignment.Center, crossAxisAlignment = CrossAxisAlignment.Center)(
text(s"count: $count", size = 24, color = Color.white),
Button("Increment", () => setCount(count + 1)),
)
}
@main def main(): Unit =
Suit.run("counter", 320, 200)(App())suit depends on a riposte checkout next to it (for the
vdom source dependency the JVM test build links) and on the system SDL3, Cairo, librsvg, and
libjpeg-turbo libraries.
# native libraries (macOS / Homebrew)
brew install sdl3 cairo librsvg jpeg-turbo
# both repos side by side
git clone https://github.com/edadma/riposte.git
git clone https://github.com/edadma/suit.git
sbt suitJVM/test # headless layout/paint/input suite (no window, no native toolchain)
sbt suitNative/run # build and launch the widget demoISC.
Bundles the Inter font (Inter 18pt Regular) under the SIL Open
Font License — see fonts/OFL.txt.