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.