Skip to main content
Go · TUI · component-based
oat-latte

oat-latte

A component-based TUI framework for Go.
Measure. Render. Ship.

$go get github.com/antoniocali/oat-latte

Two-pass layout

Measure then Render. Every component declares its size before paint — no layout thrash, predictable pixel placement every frame.

Composable widgets

Text, Button, EditText, List, CheckBox, ProgressBar, NotificationManager — all themed, all focusable, all composable via VBox/HBox/Grid.

Focus-first design

DFS focus collection, Tab/Shift-Tab cycling, proxy pattern for key interception, and FocusByRef for programmatic jumps.

Five built-in themes

Default (ANSI-16), Dark, Light, Dracula, Nord. Apply once with WithTheme — every widget inherits and can override via Style.Merge.

Modal dialogs

ShowDialog stacks overlays with a full-screen scrim. Dialogs size by fixed cells or percentage of terminal. HideDialog restores focus.

Goroutine-safe redraws

NotifyChannel lets background goroutines trigger repaints without locks. Key handlers run on the main goroutine — no races.

From zero to running in minutes

package main

import (
    "log"
    oat "github.com/antoniocali/oat-latte"
    "github.com/antoniocali/oat-latte/latte"
    "github.com/antoniocali/oat-latte/layout"
    "github.com/antoniocali/oat-latte/widget"
)

func main() {
    input := widget.NewEditText().
        WithHint("Name").
        WithPlaceholder("Type something…")

    btn := widget.NewButton("Say hello", func() {
        // handle press
    })

    body := layout.NewBorder(
        layout.NewVBox(input, btn),
    ).WithTitle("Hello")

    app := oat.NewCanvas(
        oat.WithTheme(latte.ThemeDark),
        oat.WithBody(body),
    )
    if err := app.Run(); err != nil {
        log.Fatal(err)
    }
}