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 (v0.109.0) โ€” pure-Go pixel-blitting widget set, 100+ widgets (114 in the live snapshot gallery): the GTK-4 / DaisyUI staples (Button, Entry, TreeView, Menu, Notebook, Dialog, โ€ฆ), a full chart family (Line / Bar / Pie / Area / Scatter / Radar / Sparkline, with value-on-hover crosshairs), and interactive extras โ€” Accordion, Carousel, CommandPalette, Wizard, DateRangePicker, ColorPicker, SegmentedBar, MarkdownEditor. A dashboard / data suite anchors it: a Table with cell editing, frozen columns, group rows, aggregate summaries and row-expanders; TreeTable, PropertyGrid, Kanban (drag cards) and Gantt (drag / resize bars); and an event-calendar Agenda (week / month / quarter / year) with multiple colour-coded calendars, a sidebar to toggle each on and off, and an inline event editor. A Skeleton loading-screen family covers first paint โ€” shimmering text / rectangle / circle placeholders driven by SetPhase, composed into NewSkeletonCard and full-page NewPageSkeleton shells. Lists and tables gained multi-select, virtualized rendering, and drag-to-reorder; editors gained undo/redo, IME composition, and touch/gesture input; there’s PNG export, a global clipboard, and built-in form validation. A complete container + layout-manager system rounds it out (Container + swappable Layout โ€” FitLayout/BoxLayout/BorderLayout/CardLayout/FlowLayout โ€” behind the HBox/VBox/Grid, Dock, Border (with splitters) convenience wrappers, a declarative Node builder and a ViewController). The opt-in accessibility bridge exposes role / name / value metadata, and every widget composes through a pluggable scalable Font. 100% statement coverage. LoadGTKTheme(css) parses libadwaita/GTK3 @define-color โ†’ Theme. Every widget is systematically parameterizable for placement & orientation โ€” Notebook TabSide (top/bottom/left/right), vertical ProgressBar/LevelBar/Scale/RangeSlider, Label/Table-column Align, DropDown.OpenUp, Toolbar/Steps Orientation, horizontal Timeline, and corner-anchored, stackable Toast/Notification โ€” the same widget code renders top/bottom/left/right, horizontal/vertical.

pure-Go font stack ready

Text now renders through go-opentype, a zero-dependency TrueType/OpenType engine โ€” the toolkit dropped its x/image font dependency entirely. Bundled, legible faces ship via go-opentype/fonts, with Atkinson Hyperlegible as the default Font. Same byte-buffer-first axiom: glyphs rasterize straight into the caller’s pixel buffer, no C font library, no system font lookup required.

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 (114 snapshots, light + dark). 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.