Flowik is a small Kotlin library that brings MobX-style reactive state to JVM UI toolkits. You define plain observable values and computed expressions; the UI subscribes itself and re-renders automatically when anything it reads changes — no listeners, no manual rebinding.
The library is split into a framework-agnostic core and two UI-binding modules:
| Module | Purpose |
|---|---|
flowik-core |
Reactive primitives: observables, computed, autoRun, reactions, actions |
flowik-swing |
Bindings for Swing components (depends on flowik-core) |
flowik-vaadin |
Bindings for Vaadin Flow components (depends on flowik-core) |
Most users only need one of flowik-swing or flowik-vaadin — both pull flowik-core in
transitively.
Flowik is directly inspired by MobX. The core idea, in one sentence:
Anything that can be derived from the application state should be derived. Automatically.
In practice this means three building blocks:
- Observable state — mutable values that track who reads them.
Created with
observable(...),observableMap(...),observables(...). - Derivations — pure functions over observables.
Either
computed { ... }for cached values orautoRun { ... }for side effects (typically UI updates). Both are self-wiring: they re-evaluate when — and only when — something they read has changed. - Actions —
action { ... }blocks that batch writes so derivations fire once at the end.
There is no event bus, no dependency graph you maintain by hand, no .subscribe() boilerplate at every
call site. Read an observable from inside a derivation, and you are subscribed; stop reading it and you
are not. For background and rationale, the MobX docs are
the best introduction — the mental model carries over directly.
Releases are published through JitPack. The first time a version is requested, JitPack builds it from the git tag — the badge page above shows the latest available tag and triggers a build for new ones.
repositories {
mavenCentral()
maven("https://jitpack.io")
}
dependencies {
// pick one of these:
implementation("com.github.jreznot.flowik:flowik-swing:v0.1.0")
implementation("com.github.jreznot.flowik:flowik-vaadin:v0.1.0")
}<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.jreznot.flowik</groupId>
<artifactId>flowik-swing</artifactId> <!-- or flowik-vaadin -->
<version>v0.1.0</version>
</dependency>flowik-core is pulled in transitively. You only need to declare it explicitly if you want the
reactive primitives without any UI bindings.
To follow the latest commit instead of a tagged release, use main-SNAPSHOT as the version.
A typical Flowik app has two parts: a store (plain Kotlin class holding observables and computed values) and a view that reads from the store. The view never registers listeners — it just reads, and Flowik does the rest.
import flowik.core.*
class CounterStore {
val count = observable(0)
val doubled = computed { count.value * 2 }
fun inc() = action { count.value += 1 }
}import flowik.core.*
import flowik.layout.uiFrame
import flowik.swing.*
fun main() {
val store = CounterStore()
uiFrame("Counter", width = 240, height = 120) {
center {
vbox(gap = 4) {
Label { "Count: ${store.count.value} (×2 = ${store.doubled.value})" }
Button("Increment") { store.inc() }
}
}
}
}The Label lambda reads store.count and store.doubled, so the label re-renders whenever either
changes. No explicit subscription.
import com.vaadin.flow.component.html.Span
import com.vaadin.flow.component.orderedlayout.VerticalLayout
import com.vaadin.flow.router.Route
import flowik.core.*
import flowik.vaadin.*
@Route("counter")
class CounterView : VerticalLayout() {
private val store = CounterStore()
init {
val label = Span()
label.text { "Count: ${store.count.value} (×2 = ${store.doubled.value})" }
add(label, Button("Increment") { store.inc() })
}
}The Vaadin bindings also expose two-way property binding for inputs — for example
TextField().apply { value(store::filter) } keeps a TextField in sync with an observable string
property.
From flowik-core:
val name = observable("Alice") // ObservableValue<String>
val person = observable(Person("Bob", 30)) // ObservableMap<Person> — each property reactive
val items = observables<TodoItem>() // ObservableMapList<TodoItem>
val greeting = computed { "Hello, ${name.value}" }
autoRun { println(greeting.value) } // re-runs whenever greeting changes
reaction(supply = { name.value }, effect = { newName -> println("name -> $newName") })
whenThen(check = { items.size > 10 }, effect = { println("Over the limit!") })
action { // batch — derivations fire once at the end
name.value = "Carol"
person[Person::age].value = 31
}Real, runnable demos live in the repo:
flowik-swing-demo— a Todo app showing list filtering, computed totals, keyboard navigation, and conditional visibility.flowik-vaadin-demo— the same Todo app on Vaadin Flow with property delegates and two-way input bindings.
Library sources:
flowik-core— reactive primitives.flowik-swing— Swing component bindings.flowik-vaadin— Vaadin Flow component bindings.
Apache License 2.0 — see LICENSE.