Guides/Model–Update–View

Model–Update–View

dart_tui uses the same architecture as Elm and Bubble Tea: immutable state, a pure update function, and a pure view. This makes UIs predictable and trivially testable.

The loop

text
┌──────────────┐   Msg    ┌──────────────┐
│    Model     │ ──────▶  │    update    │
│  (your state)│          │  (pure fn)   │
└──────────────┘          └──────┬───────┘
        ▲                        │ (Model, Cmd?)
        │                        ▼
        │                 ┌──────────────┐
        └──── render ───  │     view     │
                          │  (pure fn)   │
                          └──────────────┘

The pieces

ConceptDescription
ModelImmutable state. Implement init(), update(Msg) and view().
MsgA tagged event: key press, window resize, tick or custom data.
CmdFutureOr<Msg?> Function() — an async side-effect that delivers one message back.
ViewDeclared output string plus optional cursor position, mouse mode and window title.
ProgramOwns the event loop, terminal raw mode, renderer and signal handling.

update is a pure function: given the current model and a message, it returns a new model and an optional command. It never mutates state or touches the terminal directly — that's what makes it testable.

Returning a value (prompt-style)

A model can implement OutcomeModel<T> to return a value when it exits — the basis for prompts:

dart
abstract class OutcomeModel<T> implements Model {
  T? get outcome; // non-null → program exits and returns this value
}

final String? result = await Program().runForResult<String>(MyPromptModel());
Because update is pure, you can unit-test your UI by feeding it messages and asserting on the returned model — no terminal required.

Related