Installation
Add TUI to your Go module:
bash
go get tuiRequirements
- Go 1.23 or later
- Any terminal with ANSI escape sequence support
- For image features: a terminal with Kitty Graphics Protocol support (Kitty, WezTerm, or Konsole)
Quick Start
Minimal Application
Every TUI application implements the Component interface with three methods:
go
package main
import (
"log"
"tui"
)
type app struct {
message string
}
func (a *app) Init() tui.Cmd { return nil }
func (a *app) Update(msg tui.Msg) (tui.Component, tui.Cmd) {
switch msg := msg.(type) {
case tui.KeyMsg:
switch msg.Type {
case tui.KeyCtrlC:
return a, tui.QuitCmd()
case tui.KeyRune:
a.message += string(msg.Rune)
case tui.KeyBackspace:
if len(a.message) > 0 {
a.message = a.message[:len(a.message)-1]
}
}
}
return a, nil
}
func (a *app) Render(buf *tui.Buffer, area tui.Rect) {
buf.SetString(0, 0, "Type something: "+a.message, tui.NewStyle().Fg(tui.Cyan))
buf.SetString(0, 1, "Press Ctrl+C to quit", tui.NewStyle().Dim(true))
}
func main() {
if err := tui.Run(&app{}); err != nil {
log.Fatal(err)
}
}With Widgets
go
package main
import (
"log"
"tui"
"tui/widget"
)
type app struct {
list *widget.List
}
func (a *app) Init() tui.Cmd { return nil }
func (a *app) Update(msg tui.Msg) (tui.Component, tui.Cmd) {
switch msg := msg.(type) {
case tui.KeyMsg:
if msg.Type == tui.KeyCtrlC {
return a, tui.QuitCmd()
}
}
a.list, _ = a.list.Update(msg)
return a, nil
}
func (a *app) Render(buf *tui.Buffer, area tui.Rect) {
block := tui.NewBlock()
block.Title = "Pick one"
a.list.SetBlock(block)
a.list.Render(buf, area)
}
func main() {
a := &app{list: widget.NewList([]string{"Alpha", "Bravo", "Charlie"})}
if err := tui.Run(a); err != nil {
log.Fatal(err)
}
}The Elm Architecture
TUI follows the Elm Architecture pattern:
- Init — Return an optional command to run on startup (fetch data, start a timer, etc.)
- Update — Receive a message, update state, return an optional command
- Render — Draw the current state into a buffer
Messages (Msg) flow in from keyboard, mouse, resize events, and async commands. The framework handles the event loop, terminal management, and efficient rendering automatically.