Skip to content

grindlemire/go-tui

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

751 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-tui

Reactive Terminal UIs in Go

Go Reference CI License Go Report Card Coverage

Define terminal interfaces in .gsx templates with HTML-like syntax and Tailwind-style classes.
The compiler generates type-safe Go. The runtime handles flexbox layout, reactive state, and rendering.

Guides & API Reference · Examples · Editor Support

Pre-1.0: go-tui is under active development. Some APIs may evolve as the project matures.


Install

go get github.com/grindlemire/go-tui
go install github.com/grindlemire/go-tui/cmd/tui@latest

Quick look

counter.gsx

package main

import (
    "fmt"
    tui "github.com/grindlemire/go-tui"
)

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.Rune('+'), func(ke tui.KeyEvent) { c.count.Update(func(v int) int { return v + 1 }) }),
        tui.On(tui.Rune('-'), func(ke tui.KeyEvent) { c.count.Update(func(v int) int { return v - 1 }) }),
        tui.On(tui.Rune('q'), func(ke tui.KeyEvent) { ke.App().Stop() }),
    }
}

templ (c *counter) Render() {
    <div class="flex-col items-center justify-center h-full gap-1">
        <span class="font-bold text-cyan">{fmt.Sprintf("Count: %d", c.count.Get())}</span>
        <span class="font-dim">+/- to change, q to quit</span>
    </div>
}

main.go

package main

import (
    "fmt"
    "os"
    tui "github.com/grindlemire/go-tui"
)

func main() {
    app, err := tui.NewApp(tui.WithRootComponent(Counter()))
    if err != nil {
        fmt.Fprintf(os.Stderr, "%v\n", err)
        os.Exit(1)
    }
    defer app.Close()
    if err := app.Run(); err != nil {
        fmt.Fprintf(os.Stderr, "%v\n", err)
        os.Exit(1)
    }
}
tui generate counter.gsx
go run .

The generate command compiles .gsx files into plain Go source (*_gsx.go) that you can read, debug, and commit.

What's in the box

  • .gsx templates with HTML-like elements and Tailwind-style utility classes, compiled to type-safe Go
  • Pure Go flexbox layout without CGO: row, column, justify, align, gap, padding, margin, percentage widths, min/max constraints
  • Generic State[T] with automatic re-rendering, batched updates, and bindings
  • Struct components with keyboard/mouse handlers, watchers for timers and channels, refs, and a {children...} slot
  • Modal dialogs with backdrop, focus trapping, and preemptive key handling
  • Language server, formatter, and tree-sitter grammar for VS Code
  • Only depends on golang.org/x/{sys,tools}, pure Go from terminal to layout

How it works

.gsx files
    │  tui generate
    ▼
Go source (*_gsx.go)
    │  go build
    ▼
Widget tree + flexbox layout engine
    │
    ▼
Double-buffered character grid
    │  diff-based updates
    ▼
Terminal (ANSI escape sequences)

The .gsx compiler runs at build time and produces regular Go files. At runtime, the program builds a tree of *tui.Element nodes. The layout engine positions them with flexbox, and a double-buffered renderer diffs the output to minimize terminal writes.

Examples

The examples/ directory has runnable programs for each feature area. Examples 01 through 23 accompany the guides.

Example What it covers
01-getting-started Minimal component, gradient text, quit handling
02-gsx-syntax GSX file structure, templ syntax, control flow
03-styling Colors, text styles, borders, conditional styling
04-layout Flexbox row/column, justify, align, reusable layouts
05-elements Built-in elements, disabled state, progress bars
06-state State[T], if/for/:= bindings, reactive children, modal dialog
07-components Component composition, tabs, {children...} slot
08-events Keyboard event handling, KeyMap, OnKey/OnRune
09-refs-and-clicks Refs, click handling, mouse + keyboard, modal with onActivate
10-scrolling Scrollable containers, keyboard navigation
11-focus Focus management, tab cycling
12-watchers Interval timers, channel watchers, live data
13-testing Unit testing components
14-multi-component Multi-file components, shared state
15-inline-mode Inline terminal rendering mode
16-streaming Auto-scroll, stick-to-bottom, streaming data
17-inline-streaming Inline mode with streaming content
18-dashboard Metrics, sparklines, scrollable event log
19-print One-shot rendering, print and exit
20-animation Frame-cycling spinners, eased progress, color wave, pulsing border
21-directory-tree Foldable directory tree, lazy loading, scroll-to-cursor, path highlighting
22-event-loop Custom event loops via Open, Step, Events, Dispatch, Render
23-event-dump Diagnostic event log for verifying key, mouse, and resize handling

See also ai-chat and docs-example.

cd examples/01-getting-started && go run .

CLI

tui generate [path...]       Compile .gsx files to Go source
tui check [path...]          Validate without generating
tui fmt [path...]            Format .gsx files in place
tui fmt --check [path...]    Check formatting without modifying
tui lsp                      Start the language server (stdio)
tui version                  Print version

tui generate ./... compiles all .gsx files under the current directory.

Editor support

VS Code: Install the extension from editor/vscode/. Syntax highlighting, completion, hover, go-to-definition, diagnostics, and formatting.

Neovim: Install the plugin from editor/nvim/. Syntax highlighting via tree-sitter, LSP integration, and filetype detection. See the Neovim README for setup instructions.

Helix: Tree-sitter grammar at editor/tree-sitter-gsx/.

The tui lsp language server works with any editor that speaks JSON-RPC over stdio. It proxies Go-specific features through gopls with .gsx to .go source mapping.

Documentation

Guides, syntax reference, and API docs: go-tui.dev

Why are there so many files?

I wanted the imports to all be at the root so there is only a single package for the user to import and worry about (rather than an elements, styles, layout, etc.). Go Unfortunately doesn't have any indirection semantics for imports so I had to put a bunch of files in the root.

License

MIT