# go-tui — Complete Reference for LLMs > Declarative terminal UI framework for Go with templ-like syntax and flexbox layout. > Pure Go, minimal dependencies, generates type-safe code from `.gsx` templates. ## Installation ```bash go get github.com/grindlemire/go-tui go install github.com/grindlemire/go-tui/cmd/tui@latest ``` ## CLI Commands ```bash tui generate [path...] # Generate Go code from .gsx files tui check [path...] # Validate .gsx files without writing output tui fmt [path...] # Format .gsx files tui fmt --check [path...] # Check formatting without modifying tui lsp # Start language server (stdio) ``` ## Architecture ``` .gsx files → tui generate → _gsx.go files → go build → binary ``` At runtime: Event Loop → Layout Engine (flexbox) → Double-buffered Render → ANSI Terminal Output ## GSX Syntax `.gsx` files are Go files with a `templ` keyword for declaring UI components. They compile to standard Go code. ### Pure Components (stateless) ```gsx package main import tui "github.com/grindlemire/go-tui" templ Greeting(name string) { {"Hello, " + name} } // With children slot templ Card(title string) {
{title} {children...}
} // Usage templ App() { @Card("Info") { @Greeting("Alice") } } ``` ### Struct Components (stateful) ```gsx type counter struct { count *tui.State[int] } func Counter() *counter { return &counter{count: tui.NewState(0)} } func (c *counter) KeyMap() tui.KeyMap { return tui.KeyMap{ tui.On(tui.KeyEscape, func(ke tui.KeyEvent) { ke.App().Stop() }), tui.On(tui.Rune('+'), func(ke tui.KeyEvent) { c.count.Update(func(v int) int { return v + 1 }) }), } } templ (c *counter) Render() {
{fmt.Sprintf("Count: %d", c.count.Get())}
} ``` ### Struct Components with Children ```gsx type panel struct { title string children []*tui.Element } func NewPanel(title string, children []*tui.Element) *panel { return &panel{title: title, children: children} } templ (p *panel) Render() {
{p.title} {children...}
} ``` ### Control Flow ```gsx // Conditionals if condition { True } else if otherCondition { Other } else { Default } // Loops for i, item := range items { {fmt.Sprintf("%d: %s", i, item)} } // Local element binding badge := {label}
{badge}
``` ### Go Expressions ```gsx {fmt.Sprintf("Count: %d", c.count.Get())} Dynamic class
content
``` ## main.go Pattern ```go package main import ( "fmt" "os" tui "github.com/grindlemire/go-tui" ) func main() { app, err := tui.NewApp( tui.WithRootComponent(MyComponent()), // Optional: // tui.WithMouse(), // tui.WithFrameRate(60), // tui.WithInlineHeight(10), // tui.WithGlobalKeyHandler(func(ke tui.KeyEvent) bool { return false }), ) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } defer app.Close() if err := app.Run(); err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) } } ``` ## Single-Frame Printing For CLI tools that render styled output once and exit, without starting an interactive app: ```go // Print to stdout (auto-detects terminal width, falls back to 80) tui.Print(MyComponent("hello")) // Return as ANSI string (no trailing newline) s := tui.Sprint(view, tui.WithPrintWidth(80)) // Write to any io.Writer (appends trailing newline) tui.Fprint(w, view, tui.WithPrintWidth(120)) ``` All three accept a `Viewable` (generated `.gsx` views and raw `*Element` values). Same components work with both `Print` and `App.Run()`. ```go // PrintOption tui.WithPrintWidth(w int) // Explicit width; default: auto-detect, fallback 80 ``` ## Built-in Elements ### Container Elements | Element | Description | Default Direction | |---------|-------------|-------------------| | `
` | Block flex container (primary layout element) | Row | | `` | Inline text container | — | | `

` | Paragraph with automatic text wrapping | — | | `