FlowUI is a desktop UI framework for Go, built on Gio. It combines a typed MVU runtime with official widgets, layout primitives, declarative styles, window management, asynchronous effects, and deterministic UI testing through focused public packages.
import (
"github.com/qianniancn/flowui/layout"
"github.com/qianniancn/flowui/style"
"github.com/qianniancn/flowui/theme"
"github.com/qianniancn/flowui/ui"
"github.com/qianniancn/flowui/widget/button"
"github.com/qianniancn/flowui/window"
)A workspace composed with FlowUI widgets: navigation, charts, forms, date selection, selectable tables, and progress indicators.
- Typed MVU: keep business state in a model, describe changes with messages, and render a read-only view.
- Desktop components: forms, navigation, overlays, data display, charts, window chrome, and layout primitives.
- Declarative styling: theme tokens, light and dark themes, component parts, runtime states, transitions, and scoped styles.
- Application runtime: commands, subscriptions, multiple windows, retained models, and localization.
- Platform services: optional packages provide native file dialogs, desktop notifications, and system tray integration.
- Testable by design: deterministic frame, input, time, and application
helpers are available in
uitest.
- Go 1.26.2 or newer
- A desktop platform supported by Gio
go get github.com/qianniancn/flowui/uiCreate main.go inside a Go module:
package main
import (
"fmt"
"github.com/qianniancn/flowui/layout"
"github.com/qianniancn/flowui/theme"
"github.com/qianniancn/flowui/ui"
"github.com/qianniancn/flowui/widget/button"
"github.com/qianniancn/flowui/widget/text"
"github.com/qianniancn/flowui/window"
)
type Model struct {
Count int
}
type Msg interface{ msg() }
type Inc struct{}
type Dec struct{}
func (Inc) msg() {}
func (Dec) msg() {}
func Update(model *Model, msg Msg) ui.Cmd[Msg] {
switch msg.(type) {
case Inc:
model.Count++
case Dec:
model.Count--
}
return nil
}
func View(_ *ui.Context, model Model, send ui.Send[Msg]) ui.Widget {
return layout.Center(
layout.Column(
text.New("FlowUI Counter").Size(24),
text.New(fmt.Sprintf("Count: %d", model.Count)),
layout.Row(
button.New("-1").OnClick(func() {
send(Dec{})
}),
button.New("+1").OnClick(func() {
send(Inc{})
}),
).Gap(8),
).Gap(12),
)
}
func main() {
ui.Run(ui.NewProgram(Model{}, Update, View),
window.Theme(theme.Light()),
window.Title("FlowUI Counter"),
window.Size(640, 480),
)
}Run it with:
go run .For a guided walkthrough, read the English Quick Start.
FlowUI follows three ownership rules:
- Model, messages, and Update own business state. View reads a model value and sends typed messages instead of mutating captured state.
- Style owns a widget's box and appearance. Layout containers own how children are measured and positioned.
- Keys provide identity across frames. Stable keys retain interaction and animation state for repeated or moving widgets.
Choose the application API that matches the required lifecycle:
| API | Use it for |
|---|---|
ui.Run(ui.Program) |
The single-window entry point for every MVU program |
ui.NewProgram |
A compact program declaration for a fixed initial model |
ui.Application |
Multiple windows, tray integration, and application-owned lifecycles |
Commands run outside the event loop and return results through ui.Send.
Subscriptions represent long-lived inputs such as timers or external event
streams. The MVU guide
and effects guide
cover the complete contracts.
| Area | Included APIs |
|---|---|
| Content | text.New, text.NewLabel, text.NewDescription, image.New, avatar.New, badge.New, chip.New |
| Actions | button.New, button.Group, toggle.NewToggleButton, toggle.NewSegmented, button.NewCloseButton |
| Forms | input.New, input.NewTextArea, toggle.NewCheckbox, toggle.NewSwitch, radiogroup.New, selector.New, combobox.New, date and color pickers |
| Navigation | tabs.New, sidebar.New, tree.New, menu.New, menubar.New, navigation.NewPagination, navigation.NewBreadcrumb, toolbar.New |
| Overlays | dropdown.New, menu.ContextMenu, popover.New, tooltip.New, modal.New, alertdialog.New, toast.NewItem |
| Data and feedback | table.New, progress.Bar, progress.Circle, progress.Meter, spinner.New, slider.New, charts, heatmap.New, gantt.New |
| Layout | layout.Box, surface.New, surface.NewCard, surface.NewPanel, layout.Row, layout.Column, layout.Grid, layout.Scroll, splitpane.New, layout.Stack, layout.Overlay |
See the component guide for the complete widget catalog.
Styles are immutable declarations that draw colors from the active theme and respond to runtime state. The same declaration follows the active light or dark theme:
activeTheme := theme.Light()
primary := style.New().
Background(style.Solid(activeTheme.Colors.Tones[theme.TonePrimary].Fill)).
TextColor(style.Solid(activeTheme.Colors.Tones[theme.TonePrimary].OnFill)).
Radius(8).
Cursor(style.CursorPointer).
On(style.Hovered, style.New().Background(style.Solid(activeTheme.Colors.Tones[theme.TonePrimary].Hover))).
On(style.Pressed, style.New().Background(style.Solid(activeTheme.Colors.Tones[theme.TonePrimary].Pressed)).Scale(0.96))
save := button.New("Save").Style(primary)The runtime requires an explicit theme. Pass window.Theme(theme.Light()) or
window.Theme(theme.Dark()); use window.CustomizeTheme for focused token
changes. Component packages supply their own default appearance. Compound controls expose named
parts such as style.PartContent, style.PartTrack, style.PartIndicator,
and style.PartPanel for focused customization. FlowUI
includes English and Chinese component strings; window.LanguageAuto follows the
host language.
The style and theme guide documents precedence, parts, colors, geometry, transitions, and bundled font setup.
FlowUI uses system font fallback by default. For reproducible rendering, parse an
embedded TTF, OTF, or TTC with opentype.ParseCollection (gioui.org/font/opentype), assign the faces to
theme.Fonts.Collection, and set theme.Fonts.SystemFonts = false.
The core maintains one default design system in theme, with light and dark
modes. Applications can use theme.Light() / theme.Dark() directly or build a
custom token theme with the public theme APIs. For a different component
structure, compose the headless controls in widget/base.
| Package | Responsibility |
|---|---|
ui |
MVU program, context, widget contract, and application lifecycle |
widget/<component> |
Official fully-rendered components |
widget/base |
Headless behavior, focus, and semantics for custom designs |
layout |
Layout containers and the common box host |
style |
Immutable declarations, cascade, and tokens |
theme |
Semantic colors, geometry, typography, and motion tokens |
draw |
Low-level brushes, borders, shadows, paths, and transforms |
animation |
Reusable tween, spring, and timeline primitives |
window |
Native window options and locale configuration |
uitest |
Deterministic widget and application test harnesses |
Start with the interactive component showcase:
go run ./examples/showcase. Its 67 pages cover every public widget package,
with search, live demos, usage snippets, and light/dark modes. The interface
defaults to English and opens on the interactive workspace overview; it can be
switched to Chinese.
Focused default-theme examples also live in this module: go run ./examples/counter,
go run ./examples/buttons, go run ./examples/inputs,
go run ./examples/base_controls for headless bases with custom visuals, and
go run ./examples/close_guard for a native close-request guard.
| Resource | Purpose |
|---|---|
| Documentation | English task-oriented guide from first app through advanced features |
| 中文文档 | 中文教程和组件说明 |
| Package reference | Public Go API |
docs/architecture.md |
Dependency direction, state ownership, overlays, and effects |
explorer/README.md |
Per-window native open and save dialogs |
notify/README.md |
Cross-platform native notifications |
systray/README.md |
Cross-platform system tray lifecycle and native menus |
CONTRIBUTING.md |
Development workflow and contribution rules |
Applications use ui for MVU and widget/<component>, layout, style, draw, and
window according to responsibility. explorer, notify, and systray are
optional platform services.
Applications must not import packages under internal. The repository root
intentionally contains no Go package.
Run the complete project checks from the repository root:
go test ./...
go vet ./...uitest is intended for component and application tests; it is not required
by applications at runtime. See the testing guide.
Contributions are welcome. Read CONTRIBUTING.md before
submitting a change.
FlowUI is available under the MIT License.
