gitstack

grindlemire/go-tui code browser

5.9 KB markdown 154 lines 2026-03-23 · a47141f raw

Getting Started

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

What is go-tui

go-tui is a declarative terminal UI framework for Go. You write UI layouts in .gsx files using a templ-like syntax with HTML-style elements, and the framework handles flexbox layout, rendering, and terminal input. It's pure Go with minimal external dependencies and generates type-safe code from your templates.

Installation

First, add go-tui to your Go module:

go get github.com/grindlemire/go-tui

Then install the tui CLI tool, which compiles .gsx files into Go code:

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

Make sure $GOPATH/bin (or $GOBIN) is in your PATH so the tui command is available.

Editor Setup

For VS Code (or compatible editors like Cursor), install the official extension. It provides LSP support for .gsx files:

For Neovim and other editors, see the Editor Integration section in the CLI reference.

Your First App

This walks through building a "Hello, Terminal!" app from scratch.

1. Create the project

mkdir hello-tui && cd hello-tui
go mod init hello-tui
go get github.com/grindlemire/go-tui

2. Write hello.gsx

Create a file called hello.gsx:

package main

import tui "github.com/grindlemire/go-tui"

type helloApp struct{}

func Hello() *helloApp {
	return &helloApp{}
}

func (h *helloApp) KeyMap() tui.KeyMap {
	return tui.KeyMap{
		tui.On(tui.KeyEscape, func(ke tui.KeyEvent) { ke.App().Stop() }),
		tui.On(tui.Rune('q'), func(ke tui.KeyEvent) { ke.App().Stop() }),
	}
}

templ (h *helloApp) Render() {
	<div class="flex-col items-center justify-center h-full">
		<div class="border-rounded border-cyan p-2 gap-1 flex-col items-center">
			<span class="text-cyan font-bold">Hello, Terminal!</span>
			<br />
			<span class="font-dim">Press q to quit</span>
		</div>
	</div>
}

This defines a struct component called helloApp. The templ keyword declares a Render method that returns a UI tree. Inside it, you use HTML-like elements (<div>, <span>, <br />) with Tailwind-style classes for layout and styling.

The outer <div> fills the full terminal height (h-full) and centers its children both horizontally (items-center) and vertically (justify-center). The inner <div> draws a rounded cyan border with padding and arranges its children in a column.

The KeyMap() method defines keyboard bindings. tui.On with a Key constant matches special keys like Escape, and tui.On with tui.Rune('x') matches printable characters. Each handler receives a KeyEvent with access to the app instance, so ke.App().Stop() exits the event loop and shuts down cleanly.

3. Write main.go

Create main.go:

package main

import (
	"fmt"
	"os"

	tui "github.com/grindlemire/go-tui"
)

func main() {
	app, err := tui.NewApp(
		tui.WithRootComponent(Hello()),
	)
	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)
	}
}

tui.NewApp creates the application and puts the terminal into raw mode on an alternate screen. tui.WithRootComponent tells it which component to render. app.Run() starts the event loop and blocks until the app stops, and app.Close() restores the terminal to its original state.

4. Generate and run

Compile the .gsx file, then run the app:

tui generate hello.gsx
go run .

You should see a centered box with "Hello, Terminal!" in cyan. Press q or Escape to exit.

Getting Started screenshot

How It Works

You write .gsx files using templ-like syntax, then tui generate compiles them into _gsx.go files containing standard Go code that calls the tui package API. From there, go build produces a single binary with no runtime dependencies. At runtime, the framework handles the event loop, flexbox layout, and double-buffered terminal rendering.

The generated _gsx.go files are recreated every time you run tui generate and should not be edited by hand.

Core Concepts

Components come in two flavors. Pure components (templ Greeting(name string) { ... }) are stateless functions that take parameters and return UI. Struct components carry their own state, handle input, and support lifecycle hooks. See GSX Syntax and Components.

Elements are the HTML-like tags you use in .gsx files: <div> for block containers, <span> for inline text, <input /> for text fields, <progress /> for progress bars, and more. See GSX Syntax.

Styling uses Tailwind-inspired classes in the class attribute. Apply text colors (text-cyan), font styles (font-bold), borders (border-rounded), backgrounds (bg-red), and gradients (text-gradient-cyan-magenta). See Styling and Colors.

Layout follows the CSS flexbox model. Every <div> is a flex container. Control direction (flex-col), alignment (items-center, justify-between), spacing (gap-2, p-1), and sizing (w-full, h-full, grow) through classes or attributes. See Layout.

State is managed with the generic State[T] type. Create it with tui.NewState(initialValue), read with .Get(), write with .Set() or .Update(). When state changes, the UI re-renders automatically. See State and Reactivity.

Events cover keyboard and mouse input. Implement KeyMap() for key bindings (as shown above) or HandleMouse() for clicks and scrolling. See Event Handling.

Next Steps

  • GSX Syntax — The full .gsx file format: elements, attributes, control flow, and code generation
  • Styling and Colors — Text styles, colors, borders, and gradients