A modern GUI framework for Go.
Build modern, cross-platform applications entirely in Go — no browser runtime, no JavaScript, HTML, or CSS.
Write your UI entirely in Go. Your data stays in Go structs. Your UI stays in Go code. Render with native GPU acceleration — Metal on macOS, cgo-free OpenGL on Linux and Windows, and WebGL/WASM in the browser.
https://go-gui.com · Documentation · Showcase
Explore the widgets, layouts, animation, text rendering, and other capabilities interactively. Every demo includes built-in documentation.
Open the Showcase → Zero install. Instant evaluation.
Your UI is Go code. Your state is Go data. Your application is a Go program.
// This example demonstrates the smallest stateful go-gui app: one button and one counter.
package main
import (
"fmt"
"github.com/go-gui-org/go-gui/gui"
"github.com/go-gui-org/go-gui/gui/backend"
)
// App holds the window state. The view reads it on every frame.
type App struct {
Clicks int
}
func main() {
w := gui.SimpleWindow("Get Started", 300, 300, &App{}, func(w *gui.Window) {
w.SetView(mainView)
})
backend.Run(w)
}
// mainView builds the UI from the current state. It runs again for each frame.
func mainView(w *gui.Window) gui.View {
app := gui.State[App](w)
return gui.Column(gui.ContainerCfg{
Sizing: gui.FillFill,
HAlign: gui.HAlignCenter,
VAlign: gui.VAlignMiddle,
Content: []gui.View{
gui.Label("Hello GUI!", gui.CurrentTheme().TextStyleDisplay),
gui.Label(fmt.Sprintf("%d Clicks", app.Clicks), gui.TextStyle{}),
gui.TextButton("Click Me", func(ctx gui.EventCtx) {
// Change the state. The next frame shows the new count.
gui.State[App](ctx.Window).Clicks++
}),
},
})
}gui.Label(text, style) uses the default theme style with TextStyle{}.
gui.TextButton(label, onClick) and gui.SimpleWindow are thin convenience
forms. A TextButton takes a generated ID; a caller that names the button
(SetFocus, FindByID, tests) uses gui.Button with an explicit ID.
This is examples/get_started/main.go. See
examples/web_demo/ for the browser build.
Guides: Debugging · Theming · Testing
Go-Gui takes a different approach: a pure-Go UI with native GPU rendering. There is no browser runtime, JavaScript bridge, or web stack underneath your application.
Go-Gui is also an ecosystem of composable libraries. go-glyph handles text, go-charts handles data visualization, and go-edit provides code editing — each usable independently or together.
- 50+ widgets — buttons, inputs, sliders, tables, trees, tabs, menus, dialogs, toasts, DataGrid with CSV/XLSX/PDF export, Markdown and RTF views, SVG rendering, and more
- Virtualized data —
ListBox,Table, andTreevirtualize rows they own.VirtualListhandles rows the app builds, including rows whose height is known only during layout.Window.ScrollToIndexcan address a row that does not exist yet - GPU-accelerated rendering — Metal on macOS, OpenGL on Linux and Windows, WebGL/WASM in the browser, and Metal/UIKit on iOS
- Rich interaction — keyframe, spring, and tween animation, hero transitions, gestures, scrolling, focus management, color filters, box shadows, and blur effects
- Professional text & accessibility — text shaping, rendering, bidirectional layout, font fallback, IME, soft-keyboard hints for touch devices, spell checking, and full accessibility support
- Native application integration — file dialogs, menus, notifications, printing, PDF, system tray, frameless windows, and other platform services
- Developer tools — time-travel debugging, headless testing, headless rendering, layout inspection, and pixel-level regression testing
Build on a collection of composable Go libraries that share the same rendering pipeline and event system.
- go-charts — Interactive chart widgets. https://github.com/go-gui-org/go-charts
- go-edit — Code editor widget. https://github.com/go-gui-org/go-edit
- go-map — SMIL map widgets. https://github.com/go-gui-org/go-map
- go-term — Embeddable terminal emulator. https://github.com/go-gui-org/go-term
- go-glyph — Text rendering engine. https://github.com/go-gui-org/go-glyph
- go-kite — Desktop Bluesky client. https://github.com/go-gui-org/go-kite
- go-speedtest — Network speed test with a live dashboard. https://github.com/go-gui-org/go-speedtest
Hybrid immediate-mode UI with a retained widget tree. No virtual DOM, no diffing — each frame rebuilds the UI from your view function, then the framework handles layout, rendering, input, and state persistence.
View fn → generateViewLayout() → Layout tree
→ layoutArrange() (Fit/Fixed/Fill sizing)
→ renderLayout() (emits into w.renderers)
→ Backend (Metal on macOS; native GL on Linux/Windows; WebGL/WASM on web)
One typed state slot per window (gui.State[T](w)), plus per-widget internal
state via StateMap. See docs/architecture.md for the
full pipeline, event dispatch, and backend layer.
Every convenience form forwards to the matching Cfg struct. Use it when you
need the knobs — fonts, colors, sizing, padding, events:
w := gui.NewWindow(gui.WindowCfg{
State: &App{},
Title: "Counter",
Width: 300,
Height: 150,
MinWidth: 200, // the OS stops the resize drag here
MinHeight: 120,
OnInit: func(w *gui.Window) { w.SetView(mainView) },
})
gui.Button(gui.ButtonCfg{
ID: "counter",
Content: []gui.View{gui.Text(gui.TextCfg{Text: "Click Me"})},
Padding: gui.NewPadding(8, 16, 8, 16), // overrides Theme.PaddingButton
OnClick: func(ctx gui.EventCtx) {
gui.State[App](ctx.Window).Clicks++
},
})Requires Go 1.26+. A C toolchain (CGo) is needed only on macOS — the
Metal backend is Objective-C. Linux and Windows build fully cgo-free
(CGO_ENABLED=0 go build ./...). The desktop backends are native: Metal on
macOS, X11 + EGL on Linux, Win32 + WGL on Windows. Text shaping and
rasterization are pure Go via go-glyph. A native Wayland backend is
experimental: run with GOGUI_WAYLAND=1 (see docs/deployment.md).
go get github.com/go-gui-org/go-guiSee the Installation Guide for platform-specific instructions.
| Platform | Download |
|---|---|
| Browser (WASM) | Open Showcase — zero install, instant evaluation |
| macOS | Go-Gui-Showcase-.dmg |
| Linux | go-gui-showcase--linux-amd64.tar.gz |
| Windows | go-gui-showcase--windows-amd64.zip |
See Deploying your app to ship your own .app/.dmg,
icon-embedded .exe, or menu-installable Linux tarball.
- Install Go 1.26+ (a C toolchain too if developing on macOS; see Installation).
- Clone the repo.
- Run tests and lint:
go test ./...
go vet ./...
make lint- Open a pull request with a clear description of the change.
Planning lives in GitHub Issues and the go-gui-org project board, not a checked-in roadmap file. Browse open issues for current and planned work.
Set GOGUI_DEBUG=1 (or gui.Debug(true)) to audit every frame for duplicate
widget IDs and opt-in focusable shapes without IDs (focusable-by-default
controls take a generated ID when ID is empty). gui.DebugCategories enables
each class of finding — duplicates, missing IDs, unconsumed events, listbox
virtualization, over-stop gradients, unresolved state keys, unclaimed focus IDs,
stamp drift, dropped callbacks and links, refused window features —
independently. Set GOGUI_DEBUG_REBUILDS=1 to log why each frame rebuilds;
GOGUI_DEBUG=1 does not turn this on, because it logs normal operation.
Two more variables help with tests and manual runs. GOGUI_DEVICE_SCALE=2 uses
that device scale in place of the monitor's, so 2x layout and text bugs show on
a 1x monitor. GOGUI_EMULATE_CLIPBOARD=1 keeps the clipboard and the PRIMARY
selection inside each window, so the system clipboard does not change;
GOGUI_CLIPBOARD_TEXT sets the text it holds at the start. See the
Debugging wiki page.


