Skip to main content
TUI4J uses two complementary types to drive the event loop: messages represent things that have happened (key pressed, timer fired, data loaded), and commands represent things that should happen next (start a timer, quit, fetch data).

Messages

Message is a marker interface with no methods. Any class or record that implements it can be delivered to update.
The runtime produces built-in messages automatically. You can also define your own.

KeyPressMessage

Delivered for every key press. Use key() to get the string representation.
Common key strings: KeyPressMessage also provides type() (KeyType) and runes() for lower-level access.

WindowSizeMessage

Sent at startup and whenever the terminal is resized.
Store the window size in your model so that view() can produce layouts that fill the terminal correctly, especially when using Join.joinHorizontal or Style.width().

FocusMessage and BlurMessage

Delivered when the terminal window gains or loses focus. Requires ProgramOption.withReportFocus().

QuitMessage

A special message that causes the program to exit cleanly after the current frame is rendered. You normally produce it via a Command rather than returning it directly from update.

Custom messages

Implement Message on any class or Java record. Records are the most concise option:
Handle them with pattern matching in update:

Commands

Command is a functional interface that returns a Message when executed.
The runtime runs each command on a background thread and delivers the resulting Message back into the event loop. Commands should not update model state directly.

Returning a command from update

Built-in command factories

Command provides static factory methods for common operations:

Command.none()

Use Command.none() (or null) to signal that no command should run. Prefer Command.none() for clarity:

BatchMessage

BatchMessage runs multiple commands concurrently. Use Command.batch(...) to create one:
The runtime dispatches all batched commands simultaneously. Messages from them arrive in an unspecified order.

SequenceMessage

SequenceMessage runs commands one at a time, in order. Use Command.sequence(...) to create one:
Command.sequence executes commands serially and delivers each message as it arrives. Command.batch runs commands concurrently with no ordering guarantee. Use sequence when each step depends on the previous one completing.
Command.sequentially(...) is similar but stops after the first command that returns a non-null message:

The Elm Architecture

How Model, Update, and View fit together.

Styling with Lipgloss

Colors, borders, padding, and layout.