Go GUI Framework — Declarative UI for Go

v0.4.0

LinnUI is a concise, declarative Go GUI framework with polished defaults, reactive state, and familiar components — inspired by Flutter, SwiftUI, and Jetpack Compose, powered by Gio. No HTML. No CSS. No JavaScript.

The Go GUI library developers actually want

Go developers deserve a GUI for Go that feels modern — not a webview wrapper or a low-level drawing API. LinnUI is a declarative Go UI framework with composable widgets, typed reactive state, and semantic light and dark themes. Write your entire interface in pure Go and ship tiny static binaries with GPU-accelerated rendering. No cgo. No embedded browser.

What's new in v0.4.0

The v0.4.0 release grows LinnUI from a compact widget kit into a practical app toolkit:

  • Semantic color palette with theme-aware components and runtime light/dark switching
  • Main-axis and cross-axis alignment for Row and Column
  • Per-window Tree state scopes and multi-subscriber reactive state
  • Two-way TextField binding plus disabled input states
  • New form controls: Checkbox, Switch, Radio, and Slider
  • New surfaces: AppBar, Card, Dialog, Snackbar, and custom Scaffold overlays
  • Accessible labels, focus and keyboard behavior, plus modal input isolation
  • A component gallery and Linux CI with formatting, vet, and race tests

Why choose LinnUI for your Go GUI?

Install LinnUI v0.4.0

Requires Go 1.26+. Linux desktop builds also need Gio system libraries.

go get github.com/markschellhas/linnui/ui@v0.4.0

Quick example

package main

import (
    "log"
    "os"
    "strconv"

    "gioui.org/app"
    "gioui.org/op"

    ui "github.com/markschellhas/linnui/ui"
)

func main() {
    go func() {
        w := new(app.Window)
        tree := ui.NewTree(w)
        defer tree.Close()
        count := ui.NewState(0).Bind(w)
        if err := run(w, tree, count); err != nil {
            log.Print(err)
        }
        os.Exit(0)
    }()
    app.Main()
}

func run(w *app.Window, tree *ui.Tree, count *ui.State[int]) error {
    var ops op.Ops
    theme := ui.Light

    for {
        switch event := w.Event().(type) {
        case app.DestroyEvent:
            return event.Err
        case app.FrameEvent:
            gtx := app.NewContext(&ops, event)
            ui.Center(ui.Column([]any{
                ui.Text("Count: "+strconv.Itoa(count.Get()), ui.Style(ui.H4)),
                tree.Button("Increment",
                    ui.ButtonID("increment"),
                    ui.OnClick(func() {
                        count.Update(func(n int) int { return n + 1 })
                    }),
                ),
            }, ui.Spacing(16)))(gtx, &theme)
            event.Frame(gtx.Ops)
        }
    }
}

See the full component gallery in examples/gallery, text binding in examples/state, and runtime theme switching in examples/theme.

Frequently asked questions

What is LinnUI?
LinnUI is a concise, declarative Go GUI framework built on Gio with composable widgets, reactive state, semantic light and dark themes, and practical components for desktop, mobile, and WASM.
How is LinnUI different from webview-based Go GUI tools?
LinnUI renders natively through Gio with GPU acceleration. You get real Go GUI performance and tiny binaries — not an embedded Chromium shell.
What platforms are supported?
Windows, macOS, Linux, mobile via Gomobile, and WebAssembly — all from a single Go codebase.
What is new in LinnUI v0.4.0?
Theme-aware components, form controls, overlays, per-window Tree scopes, alignment, accessibility improvements, and a component gallery. See the release notes.
Is LinnUI production-ready?
LinnUI v0.4.0 is in early development. The API may change — see the changelog for release history. Contributions welcome.