TermUI Overview

View Source

TermUI is a direct-mode Terminal UI framework for Elixir/BEAM applications. It combines an Elm-style root with the BEAM process model and supervision primitives to build rich, interactive terminal interfaces.

What is TermUI?

TermUI provides everything you need to build terminal-based user interfaces:

  • The Elm Architecture - A proven pattern for building interactive UIs with predictable state management
  • Rich Widget Library - Pre-built components like gauges, tables, sparklines, and more
  • Declarative Styling - Fluent API for colors, attributes, and themes
  • Flexible Layout - Constraint-based layout system with automatic sizing
  • Normalized Input - Keyboard, mouse, paste, focus, resize, and custom event structs when emitted by the active terminal/host
  • Efficient Rendering - A dirty 60 FPS loop with differential Raw/custom output and full-frame TTY output

Architecture Overview


                    Your Application                      
      
                Single Elm Root                         
     init  event_to_msg  update  view               
      

                      TermUI Runtime                      
                    
    Events     Commands    Renderer               
                    

                    Terminal Layer                        
                    
   Raw/TTY     SSH Host     Screen                
                    

Core Concepts

The Elm Architecture

TermUI uses The Elm Architecture, a pattern for building interactive programs:

  1. Model - Your application state (a plain Elixir map or struct)
  2. Update - A function that takes a message and state, returns new state
  3. View - A function that renders state to the screen
defmodule Counter do
  use TermUI.Elm

  alias TermUI.Event

  def init(_opts), do: %{count: 0}

  def event_to_msg(%Event.Key{key: :up}, _state), do: {:msg, :increment}
  def event_to_msg(%Event.Key{key: :down}, _state), do: {:msg, :decrement}
  def event_to_msg(_, _), do: :ignore

  def update(:increment, state), do: {%{state | count: state.count + 1}, []}
  def update(:decrement, state), do: {%{state | count: state.count - 1}, []}

  def view(state) do
    text("Count: #{state.count}")
  end
end

Events and Messages

Terminal input (keys, mouse, resize) arrives as events. Your component converts events to messages via event_to_msg/2. Messages drive state changes through update/2.

The 1.0 runtime owns one root Elm state. Stateful widgets are embedded in that state and receive events only when the root forwards them; they are not automatically mounted as child processes.

Commands

Implemented side effects (timers, delayed messages, file reads, and quit) are represented as commands returned from update/2. The runtime executes them asynchronously and delivers results back as messages.

Rendering

The view/1 function returns a render tree - a declarative description of what should appear on screen. Raw and custom backends diff it against the previous frame; TTY uses a complete displayable frame.

Key Features

Widgets

Pre-built components for common UI patterns:

WidgetDescription
GaugeProgress bar with color zones
SparklineCompact inline trend graph
TableScrollable data table
MenuSelectable menu items
TextInputText entry field
DialogModal dialog box

Styling

Rich styling with colors and attributes:

Style.new(fg: :cyan, bg: :black, attrs: [:bold, :underline])

Supports 16 colors, 256-color palette, and true color (24-bit RGB).

Layout

Declarative constraints for flexible layouts:

stack(:horizontal, [
  {gauge, Constraint.percentage(30)},
  {table, Constraint.fill()}
])

Terminal Features

TermUI supports two backend modes with automatic selection:

  • Raw Mode - Full TUI experience with alternate screen, character-by-character input, and mouse support
  • TTY Mode - Cooked, IEx-compatible mode; the runtime still uses the alternate screen, while input may be buffered until Enter

See Getting Started: Backends for details on when each mode is used.

Requirements

  • Elixir 1.15+
  • OTP 26+ for TTY mode; OTP 28+ for native raw mode
  • A terminal emulator with ANSI support

Next Steps