{"id":42494225,"url":"https://github.com/grindlemire/go-tui","last_synced_at":"2026-06-04T00:00:39.945Z","repository":{"id":334499432,"uuid":"1141620597","full_name":"grindlemire/go-tui","owner":"grindlemire","description":"A declarative terminal UI framework for Go.","archived":false,"fork":false,"pushed_at":"2026-05-29T23:44:40.000Z","size":19493,"stargazers_count":324,"open_issues_count":2,"forks_count":9,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-30T00:19:10.552Z","etag":null,"topics":["golang","tui"],"latest_commit_sha":null,"homepage":"https://go-tui.dev","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grindlemire.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-25T05:34:29.000Z","updated_at":"2026-05-29T10:46:21.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/grindlemire/go-tui","commit_stats":null,"previous_names":["grindlemire/go-tui"],"tags_count":22,"template":false,"template_full_name":null,"purl":"pkg:github/grindlemire/go-tui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grindlemire%2Fgo-tui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grindlemire%2Fgo-tui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grindlemire%2Fgo-tui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grindlemire%2Fgo-tui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grindlemire","download_url":"https://codeload.github.com/grindlemire/go-tui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grindlemire%2Fgo-tui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33884734,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golang","tui"],"created_at":"2026-01-28T12:36:34.581Z","updated_at":"2026-06-04T00:00:39.929Z","avatar_url":"https://github.com/grindlemire.png","language":"Go","funding_links":[],"categories":["Go","Build Automation","Command Line"],"sub_categories":["Advanced Console UIs"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"docs/public/go-tui-logo-light-bg.svg\"\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/public/go-tui-logo.svg\"\u003e\n    \u003cimg alt=\"go-tui\" src=\"docs/public/go-tui-logo.svg\" width=\"310\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eReactive Terminal UIs in Go\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://pkg.go.dev/github.com/grindlemire/go-tui\"\u003e\u003cimg src=\"https://pkg.go.dev/badge/github.com/grindlemire/go-tui.svg\" alt=\"Go Reference\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/grindlemire/go-tui/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/grindlemire/go-tui/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/grindlemire/go-tui/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/grindlemire/go-tui\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://goreportcard.com/report/github.com/grindlemire/go-tui\"\u003e\u003cimg src=\"https://goreportcard.com/badge/github.com/grindlemire/go-tui\" alt=\"Go Report Card\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Define terminal interfaces in \u003ccode\u003e.gsx\u003c/code\u003e templates with HTML-like syntax and Tailwind-style classes. \u003cbr\u003e\n  The compiler generates type-safe Go. The runtime handles flexbox layout, reactive state, and rendering.\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://go-tui.dev\"\u003eGuides \u0026 API Reference\u003c/a\u003e \u0026middot;\n  \u003ca href=\"#examples\"\u003eExamples\u003c/a\u003e \u0026middot;\n  \u003ca href=\"#editor-support\"\u003eEditor Support\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003ePre-1.0\u003c/strong\u003e: go-tui is under active development. Some APIs may evolve as the project matures.\n\u003c/p\u003e\n\n---\n\n## Install\n\n```bash\ngo get github.com/grindlemire/go-tui\ngo install github.com/grindlemire/go-tui/cmd/tui@latest\n```\n\n## Quick look\n\n**counter.gsx**\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    tui \"github.com/grindlemire/go-tui\"\n)\n\ntype counter struct {\n    count *tui.State[int]\n}\n\nfunc Counter() *counter {\n    return \u0026counter{count: tui.NewState(0)}\n}\n\nfunc (c *counter) KeyMap() tui.KeyMap {\n    return tui.KeyMap{\n        tui.On(tui.Rune('+'), func(ke tui.KeyEvent) { c.count.Update(func(v int) int { return v + 1 }) }),\n        tui.On(tui.Rune('-'), func(ke tui.KeyEvent) { c.count.Update(func(v int) int { return v - 1 }) }),\n        tui.On(tui.Rune('q'), func(ke tui.KeyEvent) { ke.App().Stop() }),\n    }\n}\n\ntempl (c *counter) Render() {\n    \u003cdiv class=\"flex-col items-center justify-center h-full gap-1\"\u003e\n        \u003cspan class=\"font-bold text-cyan\"\u003e{fmt.Sprintf(\"Count: %d\", c.count.Get())}\u003c/span\u003e\n        \u003cspan class=\"font-dim\"\u003e+/- to change, q to quit\u003c/span\u003e\n    \u003c/div\u003e\n}\n```\n\n**main.go**\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"os\"\n    tui \"github.com/grindlemire/go-tui\"\n)\n\nfunc main() {\n    app, err := tui.NewApp(tui.WithRootComponent(Counter()))\n    if err != nil {\n        fmt.Fprintf(os.Stderr, \"%v\\n\", err)\n        os.Exit(1)\n    }\n    defer app.Close()\n    if err := app.Run(); err != nil {\n        fmt.Fprintf(os.Stderr, \"%v\\n\", err)\n        os.Exit(1)\n    }\n}\n```\n\n```bash\ntui generate counter.gsx\ngo run .\n```\n\nThe `generate` command compiles `.gsx` files into plain Go source (`*_gsx.go`) that you can read, debug, and commit.\n\n## What's in the box\n\n- `.gsx` templates with HTML-like elements and Tailwind-style utility classes, compiled to type-safe Go\n- Pure Go flexbox layout without CGO: row, column, justify, align, gap, padding, margin, percentage widths, min/max constraints\n- Generic `State[T]` with automatic re-rendering, batched updates, and bindings\n- Struct components with keyboard/mouse handlers, watchers for timers and channels, refs, and a `{children...}` slot\n- Modal dialogs with backdrop, focus trapping, and preemptive key handling\n- Language server, formatter, and tree-sitter grammar for VS Code\n- Only depends on `golang.org/x/{sys,tools}`, pure Go from terminal to layout\n\n## How it works\n\n```\n.gsx files\n    │  tui generate\n    ▼\nGo source (*_gsx.go)\n    │  go build\n    ▼\nWidget tree + flexbox layout engine\n    │\n    ▼\nDouble-buffered character grid\n    │  diff-based updates\n    ▼\nTerminal (ANSI escape sequences)\n```\n\nThe `.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.\n\n## Examples\n\nThe [`examples/`](examples/) directory has runnable programs for each feature area. Examples 01 through 23 accompany the [guides](https://go-tui.dev).\n\n| Example | What it covers |\n|---------|----------------|\n| [01-getting-started](examples/01-getting-started) | Minimal component, gradient text, quit handling |\n| [02-gsx-syntax](examples/02-gsx-syntax) | GSX file structure, templ syntax, control flow |\n| [03-styling](examples/03-styling) | Colors, text styles, borders, conditional styling |\n| [04-layout](examples/04-layout) | Flexbox row/column, justify, align, reusable layouts |\n| [05-elements](examples/05-elements) | Built-in elements, disabled state, progress bars |\n| [06-state](examples/06-state) | `State[T]`, `if`/`for`/`:=` bindings, reactive children, modal dialog |\n| [07-components](examples/07-components) | Component composition, tabs, `{children...}` slot |\n| [08-events](examples/08-events) | Keyboard event handling, `KeyMap`, `OnKey`/`OnRune` |\n| [09-refs-and-clicks](examples/09-refs-and-clicks) | Refs, click handling, mouse + keyboard, modal with onActivate |\n| [10-scrolling](examples/10-scrolling) | Scrollable containers, keyboard navigation |\n| [11-focus](examples/11-focus) | Focus management, tab cycling |\n| [12-watchers](examples/12-watchers) | Interval timers, channel watchers, live data |\n| [13-testing](examples/13-testing) | Unit testing components |\n| [14-multi-component](examples/14-multi-component) | Multi-file components, shared state |\n| [15-inline-mode](examples/15-inline-mode) | Inline terminal rendering mode |\n| [16-streaming](examples/16-streaming) | Auto-scroll, stick-to-bottom, streaming data |\n| [17-inline-streaming](examples/17-inline-streaming) | Inline mode with streaming content |\n| [18-dashboard](examples/18-dashboard) | Metrics, sparklines, scrollable event log |\n| [19-print](examples/19-print) | One-shot rendering, print and exit |\n| [20-animation](examples/20-animation) | Frame-cycling spinners, eased progress, color wave, pulsing border |\n| [21-directory-tree](examples/21-directory-tree) | Foldable directory tree, lazy loading, scroll-to-cursor, path highlighting |\n| [22-event-loop](examples/22-event-loop) | Custom event loops via `Open`, `Step`, `Events`, `Dispatch`, `Render` |\n| [23-event-dump](examples/23-event-dump) | Diagnostic event log for verifying key, mouse, and resize handling |\n\nSee also [`ai-chat`](examples/ai-chat) and [`docs-example`](examples/docs-example).\n\n```bash\ncd examples/01-getting-started \u0026\u0026 go run .\n```\n\n## CLI\n\n```\ntui generate [path...]       Compile .gsx files to Go source\ntui check [path...]          Validate without generating\ntui fmt [path...]            Format .gsx files in place\ntui fmt --check [path...]    Check formatting without modifying\ntui lsp                      Start the language server (stdio)\ntui version                  Print version\n```\n\n`tui generate ./...` compiles all `.gsx` files under the current directory.\n\n## Editor support\n\n**VS Code**: Install the extension from [`editor/vscode/`](editor/vscode/). Syntax highlighting, completion, hover, go-to-definition, diagnostics, and formatting.\n\n**Neovim**: Install the plugin from [`editor/nvim/`](editor/nvim/). Syntax highlighting via tree-sitter, LSP integration, and filetype detection. See the [Neovim README](editor/nvim/README.md) for setup instructions.\n\n**Helix**: Tree-sitter grammar at [`editor/tree-sitter-gsx/`](editor/tree-sitter-gsx/).\n\nThe `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.\n\n## Documentation\n\nGuides, syntax reference, and API docs: **[go-tui.dev](https://go-tui.dev)**\n\n## Why are there so many files?\n\nI 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.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrindlemire%2Fgo-tui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrindlemire%2Fgo-tui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrindlemire%2Fgo-tui/lists"}