Single-Frame Printing
Overview
Not every program needs an interactive event loop. Sometimes you want to render a styled table, a progress summary, or a formatted report once and exit. go-tui's Print, Sprint, and Fprint functions do exactly that: take a Viewable, run the flexbox layout engine, and emit ANSI-styled text to a writer. Same .gsx components you'd use in a full app.
Quick Start
Write a component in a .gsx file just like you normally would:
package main
import "fmt"
templ BuildReport(project string, status string, duration string, tests int, passed int) {
<div class="flex-row justify-center">
<div class="flex-col border-rounded border-cyan p-1 w-1/2">
<div class="flex-row justify-between">
<span class="font-bold text-cyan">{project}</span>
<span class="font-bold text-green">{status}</span>
</div>
<hr />
<div class="flex-row gap-4">
<span class="text-dim">Duration: {duration}</span>
<span class="text-dim">Tests: {fmt.Sprintf("%d/%d passed", passed, tests)}</span>
</div>
</div>
</div>
}
Generate the Go code:
tui generate report.gsx
Then call tui.Print from your main():
package main
import tui "github.com/grindlemire/go-tui"
//go:generate go run ../../cmd/tui generate report.gsx
func main() {
tui.Print(BuildReport("myapp", "PASS", "2.3s", 42, 42))
}
Run it and you get styled, bordered output printed to your terminal. The process exits immediately, just like any other CLI command.
Width Control
By default, Print detects the terminal width automatically (falling back to 80 columns if detection fails, for example when piping to a file). Override with WithPrintWidth:
// Always render at 120 columns, regardless of terminal size
tui.Print(view, tui.WithPrintWidth(120))
This is useful when:
- Piping output to a file or another process
- Generating fixed-width output for CI logs
- Testing with deterministic widths
Sprint and Fprint
Sprint returns the ANSI string instead of writing it:
s := tui.Sprint(view, tui.WithPrintWidth(80))
fmt.Println(s) // you decide where it goes
Fprint writes to any io.Writer:
var buf bytes.Buffer
tui.Fprint(&buf, view, tui.WithPrintWidth(80))
// buf now contains the ANSI-styled output
f, _ := os.Create("report.txt")
defer f.Close()
tui.Fprint(f, view, tui.WithPrintWidth(80))
Fprint appends a trailing newline so the shell prompt doesn't collide with the output. Sprint does not, so callers composing strings can manage their own newlines.
Reusing Components
The .gsx components you write for single-frame printing also work with App.Run():
// Non-interactive: print and exit
tui.Print(StatusTable(results))
// Interactive: full TUI app
app, _ := tui.NewApp(tui.WithRootComponent(Dashboard(results)))
defer app.Close()
app.Run()
Both call the same generated functions. One prints and exits, the other runs an interactive loop.

Cross-references: Testing Guide, Inline Mode Guide