Cross-platform, immediate-mode GUI framework for Go β no virtual DOM, no diffing, just fast, composable UI.
Go-Gui is an immediate-mode GUI framework where every frame, a plain Go function returns a layout tree that gets sized, positioned, and rendered directly to the screen. State lives in a single typed slot per window β no globals, no closures, no hidden magic.
Originally ported from the V-language gui library, Go-Gui keeps the same philosophy: minimal ceremony, composable widgets, and a clean separation between layout logic and rendering.
View fn β Layout tree β layoutArrange() β renderLayout() β []RenderCmd β GPU
Widgets & Layout
- 50+ built-in widgets β buttons, inputs, sliders, tables, trees, tabs, menus, dialogs, toasts, breadcrumbs, and more
- Flexible layout system β Row, Column, Wrap, Canvas, Splitter, DockLayout, ExpandPanel, OverflowPanel, RotatedBox
- DataGrid with virtualization, sorting, grouping, inline editing, CSV/TSV/XLSX/PDF export, and async data sources
- Dock layout with drag-and-drop panel rearrangement and tab groups
Rendering & Backends
- GPU-accelerated rendering via SDL2 + Metal (macOS) / OpenGL (Linux/Windows)
- Web/WASM backend β Canvas2D with custom WebGL shaders, runs in any browser
- iOS backend β Metal rendering, UIKit windowing, touch events
- Android backend support
- Custom GPU shader support
Text & Rich Content
- Rich text input β multiline, click-to-cursor, drag-to-select, word select, autoscroll, Home/End cycling
- Markdown and RTF views with syntax highlighting and code-block copy-to-clipboard
- Text selection and copy for read-only Text widgets
- SVG loading, caching, and tessellation
- Powered by go-glyph for professional-grade text shaping, rendering, and bidirectional layout
Animation & Effects
- Full animation subsystem β keyframe, spring, tween, hero transitions
- ColorFilter post-processing β grayscale, sepia, brightness, contrast, hue rotate, invert, saturation, and composable filter chains
- ClipContents β stencil-based rounded-rect clip masking
- Box shadows and blur effects
Input & Interaction
- Touch gesture recognition β tap, double-tap, long-press, pan, swipe, pinch, rotate with automatic mouse-event synthesis for compatibility
- Pan gestures auto-scroll containers; pinch/rotate available on ContainerCfg and DrawCanvasCfg
Audio
- Opt-in audio via SDL_mixer β sound effects and music playback
- Multiple mixing channels, volume control, fade in/out
- Load from file or embedded bytes (WAV, OGG, MP3, FLAC, MOD)
Platform Integration
- Windows backend β native file dialogs, print, and notifications
- OS-level spell check (macOS NSSpellChecker, Linux Hunspell)
- IME support and accessibility tree (macOS, Linux AT-SPI2)
- Multi-window support with cross-window messaging
- Native dialogs, notifications, system tray, and print/PDF
- Native menu bar support
- Locale and i18n support
- Command registry with global hotkeys and fuzzy-search command palette
Developer Experience
- Theme system with built-in dark/light variants and custom themes
- Stateless view model β views are pure functions, easy to test
- Headless test backend runs all layout and widget logic without a display
- Embedded Feather icon font with themed styles
package main
import (
"fmt"
"github.com/mike-ward/go-gui/gui"
"github.com/mike-ward/go-gui/gui/backend"
)
type App struct{ Clicks int }
func main() {
gui.SetTheme(gui.ThemeDarkBordered)
w := gui.NewWindow(gui.WindowCfg{
State: &App{},
Title: "get_started",
Width: 300,
Height: 300,
OnInit: func(w *gui.Window) { w.UpdateView(mainView) },
})
backend.Run(w)
}
func mainView(w *gui.Window) gui.View {
ww, wh := w.WindowSize()
app := gui.State[App](w)
return gui.Column(gui.ContainerCfg{
Width: float32(ww),
Height: float32(wh),
Sizing: gui.FixedFixed,
HAlign: gui.HAlignCenter,
VAlign: gui.VAlignMiddle,
Content: []gui.View{
gui.Text(gui.TextCfg{
Text: "Hello GUI!",
TextStyle: gui.CurrentTheme().B1,
}),
gui.Button(gui.ButtonCfg{
IDFocus: 1,
Content: []gui.View{
gui.Text(gui.TextCfg{
Text: fmt.Sprintf("%d Clicks", app.Clicks),
}),
},
OnClick: func(_ *gui.Layout, e *gui.Event, w *gui.Window) {
gui.State[App](w).Clicks++
e.IsHandled = true
},
}),
},
})
}See examples/get_started/ for the full runnable
version and examples/web_demo/ for the browser build.
Go-Gui requires Go 1.26+ and SDL2 development libraries.
brew install go pkg-config sdl2 sdl2_mixer freetype harfbuzz pango fontconfigsudo apt-get update
sudo apt-get install -y \
golang build-essential pkg-config \
libsdl2-dev libsdl2-mixer-dev libfreetype6-dev libharfbuzz-dev \
libpango1.0-dev libfontconfig1-devsudo dnf install -y golang gcc pkgconf-pkg-config \
SDL2-devel SDL2_mixer-devel freetype-devel harfbuzz-devel pango-devel fontconfig-develsudo pacman -Syu --noconfirm go base-devel pkgconf \
sdl2 sdl2_mixer freetype2 harfbuzz pango fontconfigpacman -S --needed mingw-w64-x86_64-go mingw-w64-x86_64-gcc \
mingw-w64-x86_64-pkgconf mingw-w64-x86_64-SDL2 \
mingw-w64-x86_64-SDL2_mixer mingw-w64-x86_64-freetype \
mingw-w64-x86_64-harfbuzz mingw-w64-x86_64-pango \
mingw-w64-x86_64-fontconfigUse the MSYS2 MinGW x64 shell for go build / go run.
vcpkg install sdl2:x64-windows sdl2-mixer:x64-windows \
freetype:x64-windows harfbuzz:x64-windows pango:x64-windows \
fontconfig:x64-windowsSet CGO_CFLAGS and CGO_LDFLAGS to the vcpkg include/lib paths before
building.
go get github.com/mike-ward/go-guibackend.Run(w) auto-selects Metal on macOS and OpenGL elsewhere:
import "github.com/mike-ward/go-gui/gui/backend"
backend.Run(w) // Metal on macOS, GL on Linux/WindowsTo force a specific backend, import it directly:
import metal "github.com/mike-ward/go-gui/gui/backend/metal" // macOS only
import gl "github.com/mike-ward/go-gui/gui/backend/gl" // cross-platform
import sdl2 "github.com/mike-ward/go-gui/gui/backend/sdl2" // software fallback
import web "github.com/mike-ward/go-gui/gui/backend/web" // WASM/browser
import ios "github.com/mike-ward/go-gui/gui/backend/ios" // iOSgui.SetTheme(gui.ThemeDark) // set globally before NewWindow
gui.SetTheme(gui.ThemeDarkBordered) // dark with visible borders
t := gui.CurrentTheme() // read anywhereCustom themes are built with gui.ThemeMaker and registered via
gui.RegisterTheme.
app := gui.NewApp()
app.ExitMode = gui.ExitOnMainClose
w1 := gui.NewWindow(gui.WindowCfg{State: &Main{}, Title: "Main"})
w2 := gui.NewWindow(gui.WindowCfg{State: &Inspector{}, Title: "Inspector"})
backend.RunApp(app, w1, w2)Open windows at runtime with app.OpenWindow(cfg). Communicate across
windows with app.Broadcast(fn) or other.QueueCommand(fn).
Per-window state via a single typed slot β no globals, no closures:
type Counter struct{ N int }
w := gui.NewWindow(gui.WindowCfg{State: &Counter{}})
// Inside any callback or view:
s := gui.State[Counter](w)
s.N++Events are wired through Cfg structs:
gui.Button(gui.ButtonCfg{
IDFocus: 1,
OnClick: func(l *gui.Layout, e *gui.Event, w *gui.Window) {
// handle click
e.IsHandled = true
},
})
gui.Input(gui.InputCfg{
OnKeyDown: func(l *gui.Layout, e *gui.Event, w *gui.Window) { β¦ },
OnCharInput: func(l *gui.Layout, e *gui.Event, w *gui.Window) { β¦ },
OnTextCommit: func(l *gui.Layout, e *gui.Event, w *gui.Window) { β¦ },
})35 example applications ship with the framework:
| Directory | Description |
|---|---|
animations |
Animation subsystem showcase |
benchmark |
Frame timing and allocation benchmarks |
blur_demo |
Blur visual effect |
calculator |
Styled desktop calculator |
color_picker |
Color picker widget |
command_demo |
Command registry, hotkeys, command palette |
context_menu |
Right-click context menus |
custom_shader |
Custom GPU shader rendering |
data_grid_data_source |
DataGrid with async data source |
date_picker_options |
Date picker configurations |
dialogs |
Native and custom dialogs |
digital_rain |
Matrix-style digital rain effect |
dock_layout |
IDE-style docking panels with drag-and-drop |
draw_canvas |
Custom-draw canvas surface |
floating_layout |
Float-anchored overlay positioning |
get_started |
Minimal hello-world app |
gradient_demo |
OpenGL gradient rendering |
ios_demo |
iOS demo app (Metal + UIKit) |
listbox |
ListBox widget demo |
markdown |
Markdown rendering with code-block copy |
menu_demo |
Pull-down menu bar |
multi_window |
Multi-window with cross-window messaging |
multiline_input |
Multiline text input |
native_menu |
OS-native menu bar |
rotated_box |
Quarter-turn rotation widget |
rtf |
RTF document viewer |
scroll_demo |
Scrollable content layouts |
shadow_demo |
Box shadow effects |
showcase |
Interactive widget showcase |
snake |
Snake game |
svg |
SVG loading and display |
system_tray |
System tray icon and menu |
todo |
Classic todo app |
web_demo |
Browser demo via WASM |
Run any example:
go run ./examples/get_started/
go run ./examples/showcase/
go run ./examples/calculator/| Widget | Factory | Description |
|---|---|---|
| Row | Row(ContainerCfg) |
Horizontal flex container |
| Column | Column(ContainerCfg) |
Vertical flex container |
| Wrap | Wrap(ContainerCfg) |
Flow-wrap container |
| Canvas | Canvas(ContainerCfg) |
Absolute-position canvas |
| Circle | Circle(ContainerCfg) |
Circular container |
| Rectangle | Rectangle(RectangleCfg) |
Styled rectangle |
| ExpandPanel | ExpandPanel(ExpandPanelCfg) |
Collapsible section |
| Splitter | Split(SplitterCfg) |
Resizable two-pane split |
| DockLayout | DockLayout(DockCfg) |
Drag-and-drop dock areas |
| OverflowPanel | OverflowPanel(OverflowPanelCfg) |
Wraps overflowing children |
| RotatedBox | RotatedBox(RotatedBoxCfg) |
Quarter-turn rotation |
| Widget | Factory | Description |
|---|---|---|
| Button | Button(ButtonCfg) |
Clickable button |
| Input | Input(InputCfg) |
Single-line text field |
| NumericInput | NumericInput(NumericInputCfg) |
Numeric text field |
| Checkbox | Checkbox(CheckboxCfg) |
Boolean toggle |
| Radio | Radio(RadioCfg) |
Mutually-exclusive options |
| Select | Select(SelectCfg) |
Dropdown selector |
| Combobox | Combobox(ComboboxCfg) |
Editable dropdown |
| Switch | Switch(SwitchCfg) |
On/off toggle switch |
| Toggle | Toggle(ToggleCfg) |
Toggle button |
| Slider | Slider(SliderCfg) |
Min/max range picker |
| InputDate | InputDate(InputDateCfg) |
Date field with picker |
| ColorPicker | ColorPicker(ColorPickerCfg) |
RGBA color picker |
| Form | Form(FormCfg) |
Form with validation |
| ThemePicker | ThemePicker(ThemePickerCfg) |
Theme switcher |
| CommandPalette | CommandPalette(CommandPaletteCfg) |
Fuzzy-search command palette |
| Widget | Factory | Description |
|---|---|---|
| Text | Text(TextCfg) |
Styled text label |
| Badge | Badge(BadgeCfg) |
Notification badge |
| ProgressBar | ProgressBar(ProgressBarCfg) |
Determinate/indeterminate bar |
| Pulsar | Pulsar(PulsarCfg) |
Blinking cursor indicator |
| DrawCanvas | DrawCanvas(DrawCanvasCfg) |
Custom-draw surface |
| Image | Image(ImageCfg) |
Raster image view |
| Svg | Svg(SvgCfg) |
SVG vector image view |
| Markdown | w.Markdown(MarkdownCfg) |
Rendered Markdown |
| RTF | RTF(RtfCfg) |
Rendered RTF |
| Widget | Factory | Description |
|---|---|---|
| ListBox | ListBox(ListBoxCfg) |
Scrollable item list |
| Table | Table(TableCfg) |
Static data table |
| DataGrid | w.DataGrid(DataGridCfg) |
Virtualized grid with full CRUD |
| Tree | Tree(TreeCfg) |
Hierarchical tree view |
| DatePicker | DatePicker(DatePickerCfg) |
Calendar date picker |
| DatePickerRoller | DatePickerRoller(DatePickerRollerCfg) |
Drum-style date roller |
| Widget | Factory | Description |
|---|---|---|
| TabControl | Tabs(TabControlCfg) |
Tabbed panel |
| Breadcrumb | Breadcrumb(BreadcrumbCfg) |
Navigational breadcrumb trail |
| Menu | Menu(MenuCfg) |
Pull-down menu bar |
| Menubar | Menubar(w, MenubarCfg) |
Application menu bar |
| ContextMenu | ContextMenu(w, ContextMenuCfg) |
Right-click context menu |
| Sidebar | w.Sidebar(SidebarCfg) |
Collapsible side navigation |
| Widget | Factory | Description |
|---|---|---|
| Dialog | w.Dialog(DialogCfg) |
Modal dialog |
| Toast | w.Toast(ToastCfg) |
Transient notification |
| WithTooltip | WithTooltip(w, WithTooltipCfg) |
Hover tooltip wrapper |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application Layer β
β examples/ ββ View fn(w *Window) *Layout β
β gui.State[T](w) typed state slot β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββββββββββΌβββββββββββββββββββββββββββββββββ
β gui/ (core package) β
β β
β ββββββββββββββββ ββββββββββββββββ βββββββββββββββββ β
β β Widgets β β State Mgmt β β Animation β β
β β Button,Text β β StateMap β β Subsystem β β
β β Containerβ¦ β β per-window β β β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ βββββββββ¬ββββββββ β
β β β β β
β ββββββββΌββββββββββββββββββΌβββββββββββββββββββΌββββββββ β
β β Layout Engine β β
β β GenerateViewLayout() β Layout tree β β
β β layoutArrange() β Fit/Fixed/Grow sizing β β
β β renderLayout() β []RenderCmd β β
β ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββΌβββββββββββββββββββββββββββββ β
β β Event Dispatch β β
β β Mouse Β· Keyboard Β· Focus Β· Scroll β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββββ
β
ββββββββββββββββββΌββββββββββββββββββ
β β β
βββββββββΌβββββββ βββββββββΌβββββββ ββββββββββΌββββββββ
β TextMeasurerβ β SvgParser β β NativePlatform β
β (interface) β β (interface) β β (interface) β
βββββββββ¬βββββββ βββββββββ¬βββββββ ββββββββββ¬ββββββββ
β β β
βββββββββΌβββββββββββββββββΌββββββββββββββββββΌββββββββββββ
β backend/sdl2/ β
β Injects interfaces at startup Β· Window management β
ββββββββββββββββ¬ββββββββββββββββ¬ββββββββββββββββββββββββ€
β backend/ β backend/gl/ β backend/filedialog/ β
β metal/ β OpenGL β backend/printdialog/ β
β Metal(macOS)β β β
ββββββββββββββββΌββββββββββββββββΌββββββββββββββββββββββββ€
β backend/ β backend/ios/ β backend/spellcheck/ β
β web/ β Metal+UIKit β backend/atspi/ β
β WASM+Canvas β (iOS) β (Linux a11y) β
ββββββββββββββββ΄ββββββββββββββββ΄ββββββββββββββββββββββββ
β
βββββββββΌββββββββ
β go-glyph β
β Text shaping β
β rendering β
β wrapping β
βββββββββββββββββ
Key types: Layout (tree node), Shape (renderable), RenderCmd
(draw op), Window (top-level + state slot)
Tests run headlessly via the gui/backend/test no-op backend β no display
server required.
# Run all tests
go test ./...
# Run a specific test
go test ./gui/... -run TestFoo
# Static analysis
go vet ./...
# Full lint suite (govet, staticcheck, errcheck, gosimple, unused,
# gofmt, goimports, revive)
golangci-lint run ./gui/...
# Build all packages
go build ./...- Install Go 1.26+ and SDL2 development libraries (see Installation).
- Clone the repo.
- Run tests and lint:
go test ./...
go vet ./...
golangci-lint run ./gui/...- Open a pull request with a clear description of the change.
PolyForm Noncommercial 1.0.0 β free for noncommercial use, personal projects, research, education, and open-source work.




