go-widgets

Pure-Go widget toolkits that render into a byte buffer. Works everywhere Go runs.

pure Go ยท CGO=0 byte-buffer first 100% statement coverage GTK-theme aware runs in js/wasm runs on native BSD-3-Clause
โ–ถ live demo toolkit repo API + widgets org
pkg.go.dev Go License

go-widgets is a family of pure-Go widget toolkits with a single design axiom: every widget renders into a caller-supplied []byte. That constraint keeps the surface dependency-free (no JS, no DOM, no canvas), which is what lets the same widget code compose pixels in a browser tab, a native window, or a headless CI test.

import (
    "github.com/go-widgets/toolkit"
    "github.com/go-widgets/painter"
)

theme := toolkit.DefaultLight()
btn := toolkit.NewButton("Click me", func() { println("clicked!") })
btn.SetBounds(toolkit.Rect{X: 20, Y: 20, W: 120, H: 28})

// A Painter is the render seam: PixelPainter โ†’ RGBA bytes (wasm/native),
// CellPainter โ†’ a terminal grid. Same widget code, either backend.
p := painter.NewPixelPainter(make([]byte, 4*width*height), width, height)
btn.Draw(p, theme)                       // pixels land in p's buffer
btn.OnEvent(toolkit.Event{Kind: toolkit.EventClick, X: 50, Y: 30})

toolkit ready

toolkit โ€” pure-Go pixel-blitting widget set, 68 widgets: the GTK-4 / DaisyUI staples (Button, Entry, TreeView, Menu, Notebook, Dialog, โ€ฆ), a chart family (LineChart / BarChart / PieChart), DatePicker, RangeSlider, MarkdownView, ContextMenu, an Overlay stacking container, drag-and-drop events, an opt-in accessibility bridge, and a pluggable scalable Font (with FontChooser). 100% statement coverage. LoadGTKTheme(css) parses libadwaita/GTK3 @define-color โ†’ Theme.

Byte-buffer first ready

Every widget composes pixels into a caller-supplied []byte. No JS, no DOM, no canvas dep at the toolkit level. Works identically in GOOS=js GOARCH=wasm (browser SharedArrayBuffer clients), on any native Go target (native canvas backends, PNG output), or in headless tests (screenshot-hash regressions).

GTK-theme aware ready

LoadGTKTheme(css) reads any GTK3 / libadwaita @define-color block (Adwaita, Juno, WhiteSur, Solarized โ€ฆ) and hands you a Theme value that cascades through every widget. One assignment, whole app repaints.

svg โ€” RGBA โ†’ SVG snapshot ready

svg โ€” wraps any RGBA render (a toolkit widget composition or any other pixel producer) in a self-contained SVG with the pixels embedded as a base-64 PNG. Bit-exact, scales crisply. Sibling svg/widget takes a toolkit.Widget directly; svg/cmd/gallery-render batch-renders every widget kind. See the live snapshot gallery. 100 % statement coverage.

gallery โ€” live wasm demo ready

gallery โ€” a browser wasm live-demo running the toolkit’s full widget family set on a plain canvas. See it at go-widgets.github.io/gallery. No SharedArrayBuffer, no COOP/COEP; drops into any static host.

tui โ€” terminal cell widgets ready

tui โ€” pure-Go cell-native widget set that renders into a terminal cell grid via a CellPainter (the same painter.Painter seam the pixel backend uses). 34 widgets + a FocusRing, plus a Sparkline mini-chart, syntax-highlighted TextEditor, and dogfooding demos (tui-explorer / tui-editor / tui-widget-explorer). Same byte-buffer-first axiom, terminal backing store. 100% statement coverage.

Every widget in the toolkit ships with a 100 % statement coverage gate. Defensive dead code the coverage tool flags gets DELETED (not annotated), so the coverage number stays honest. Builds are trivially cross-target because the whole stack is pure Go with cgo disabled โ€” no C toolchain, no runtime fetch, no vendored assets. Everything is BSD-3-Clause.