Build beautiful terminal UIs with Charmbracelet. For SHELL/BASH scripts: use Gum (prompts, spinners, selection), VHS (recording), Mods (AI), Freeze (screenshots), Glow (markdown)...
| I need to... | Use | Reference |
|---|---|---|
| Add prompts/spinners to a shell script | Gum (no Go) | Shell Scripts |
| Build a Go TUI | Bubble Tea + Lip Gloss | Go TUI |
| Build a production-grade Go TUI | Above + elite patterns | Production Architecture |
| Serve a TUI over SSH | Wish + Bubble Tea | Infrastructure |
| Record a terminal demo | VHS | Shell Scripts |
| Find a Bubbles component | list, table, viewport, spinner, progress... | Component Catalog |
| Get a copy-paste pattern | Layouts, forms, animation, testing | Quick Reference / Advanced Patterns |
Is it a shell script?
āā Yes ā Use Gum
ā Need recording? ā VHS
ā Need AI? ā Mods
ā
āā No (Go application)
ā
āā Just styled output? ā Lip Gloss only
āā Simple prompts/forms? ā Huh standalone
āā Full interactive TUI? ā Bubble Tea + Bubbles + Lip Gloss
ā ā
ā āā Production-grade? ā Also add elite patterns:
ā (multi-view, data- two-phase async, immutable snapshots,
ā dense, must be adaptive layout, focus state machine,
ā fast & polished) semantic theming, pre-computed styles
ā ā See Production Architecture reference
ā
āā Need SSH access? ā Wish + Bubble Tea
brew install gum # One-time install
# Input
NAME=$(gum input --placeholder "Your name")
# Selection
COLOR=$(gum choose "red" "green" "blue")
# Fuzzy filter from stdin
BRANCH=$(git branch | gum filter)
# Confirmation
gum confirm "Continue?" && echo "yes"
# Spinner
gum spin --title "Working..." -- long-command
# Styled output
gum style --border rounded --padding "1 2" "Hello"
Full Gum Reference ā VHS Recording ā Mods AI ā
go get github.com/charmbracelet/bubbletea github.com/charmbracelet/lipgloss
package main
import (
"fmt"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
var highlight = lipgloss.NewStyle().Foreground(lipgloss.Color("212")).Bold(true)
type model struct {
items []string
cursor int
}
func (m model) Init() tea.Cmd { return nil }
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
case "up", "k":
if m.cursor > 0 { m.cursor-- }
case "down", "j":
if m.cursor < len(m.items)-1 { m.cursor++ }
case "enter":
fmt.Printf("Selected: %s\n", m.items[m.cursor])
return m, tea.Quit
}
}
return m, nil
}
func (m model) View() string {
s := ""
for i, item := range m.items {
if i == m.cursor {
s += highlight.Render("āø "+item) + "\n"
} else {
s += " " + item + "\n"
}
}
return s + "\n(ā/ā move, enter select, q quit)"
}
func main() {
m := model{items: []string{"Option A", "Option B", "Option C"}}
tea.NewProgram(m).Run()
}
| Need | Library | Example |
|---|---|---|
| TUI framework | bubbletea |
tea.NewProgram(model).Run() |
| Components | bubbles |
list.New(), textinput.New() |
| Styling | lipgloss |
style.Foreground(lipgloss.Color("212")) |
| Forms | huh |
huh.NewInput().Title("Name").Run() |
| Markdown | glamour |
glamour.Render(md, "dark") |
| Animation | harmonica |
harmonica.NewSpring() |
Full Go TUI Guide ā All Bubbles Components ā Layout & Animation Patterns ā
s, _ := wish.NewServer(
wish.WithAddress(":2222"),
wish.WithHostKeyPath(".ssh/key"),
wish.WithMiddleware(
bubbletea.Middleware(handler),
logging.Middleware(),
),
)
s.ListenAndServe()
Connect: ssh localhost -p 2222
Beyond basic Bubble Tea: patterns that make TUIs feel fast, polished, and professional. Each links to a full code example in Production Architecture.
| Symptom | Pattern | Fix |
|---|---|---|
| UI blocks during computation | Two-Phase Async | Phase 1 instant, Phase 2 background goroutine |
| Render path holds mutex | Immutable Snapshots | Pre-build snapshot, atomic pointer swap |
| File changes cause stutter | Background Worker | Debounced watcher + coalescing |
| Thousands of allocs per frame | Pre-Computed Styles | Allocate delegate styles once at startup |
| O(n²) string concat in View() | strings.Builder | Pre-allocated Builder with Grow() |
| Glamour re-renders every frame | Cached Markdown | Cache by content hash, invalidate on width change |
| GC pauses during interaction | Idle-Time GC | Trigger GC during idle periods |
| Large dataset = high memory | Object Pooling | sync.Pool with pre-allocated slices |
| Rendering off-screen items | Viewport Virtualization | Only render visible rows |
| Symptom | Pattern | Fix |
|---|---|---|
| Hardcoded widths break | Adaptive Layout | 3-4 responsive breakpoints (80/100/140/180 cols) |
| Colors wrong on light terminals | Semantic Theming | lipgloss.AdaptiveColor + WCAG AA contrast |
| Items have equal priority ā list shuffles | Deterministic Sorting | Stable sort with tie-breaking secondary key |
| Sort mode not visible | Dynamic Status Bar | Left/right segments with gap-fill |
| Symptom | Pattern | Fix |
|---|---|---|
| Key routing chaos | Focus State Machine | Explicit focus enum + modal priority layer |
| User gets lost in nested views | Breadcrumb Navigation | Home > Board > Priority path indicator |
| Overlay dismiss loses position | Focus Restoration | Save focus before overlay, restore on dismiss |
| Old async results overwrite new data | Stale Message Detection | Compare data hash before applying results |
| Multiple component updates per frame | tea.Batch Accumulation | Collect cmds in slice, return tea.Batch(cmds...) |
| Background goroutine panic kills TUI | Error Recovery | defer/recover wrapper for all goroutines |
| Want | Pattern | Code |
|---|---|---|
| Bar charts in list columns | Unicode Sparklines | āā
ā using 8-level block characters |
| Color-by-intensity | Perceptual Heatmaps | gray ā blue ā purple ā pink gradient |
| Dependency graph in terminal | ASCII Graph Renderer | Canvas + Manhattan routing (āāā®āā°āÆ) |
| Age at a glance | Age Color Coding | Fresh=green, aging=yellow, stale=red |
| Borders that mean something | Semantic Borders | Red=blocked, green=ready, yellow=high-impact |
| Want | Pattern | Key Idea |
|---|---|---|
Vim-style gg/G |
Vim Key Combos | Track waitingForG state between keystrokes |
| Search without jank | Debounced Search | 150ms timer, fire only when typing stops |
| Search across all fields at once | Composite FilterValue | Flatten all fields into one string |
| 4-line cards with metadata | Rich Delegates | Custom delegate with Height()=4 |
| Expand detail inline | Inline Expansion | Toggle with d, auto-collapse on j/k |
| Copy to clipboard | Clipboard Integration | y for ID, C for markdown + toast feedback |
? / ` / ; help |
Multi-Tier Help | Quick ref + tutorial + persistent sidebar |
| Kanban with mode switching | Kanban Swimlanes | Pre-computed board states, O(1) switch |
| Collapsible tree with h/l | Tree Navigation | Flatten tree to visible list for j/k nav |
| Suspend TUI for vim edit | Editor Dispatch | tea.ExecProcess for terminal, background for GUI |
| Remember expand/collapse | Persistent State | Save to JSON, graceful degradation on corrupt |
| Tune via env vars | Env Preferences | NO_COLOR, theme, debounce, split ratio |
| Optional feature missing? | Graceful Degradation | Detect at startup, hide unavailable features |
Full Production Architecture Guide ā
tea.WindowSizeMsg ā resize all componentsctrl+c ā cleanup, restore terminal state--no-tui / NO_TUI escape hatchNO_COLOR=1 and TERM=dumbFor production TUIs, see the full checklist (16 must-have + 20 polish items).
mytool | grep ā plain textfmt.Scanf is fineEscape hatch:
if !term.IsTerminal(os.Stdin.Fd()) || os.Getenv("NO_TUI") != "" {
runPlainMode()
return
}
| I need... | Read this |
|---|---|
| Copy-paste one-liners | Quick Reference |
| Prompts to give Claude for TUI tasks | Prompts |
| Gum / VHS / Mods / Freeze / Glow | Shell Scripts |
| Bubble Tea architecture, debugging, anti-patterns | Go TUI |
| Bubbles component APIs (list, table, viewport...) | Component Catalog |
| Theming, layouts, animation, Huh forms, testing | Advanced Patterns |
| Elite patterns: async, snapshots, focus machines, adaptive layout, sparklines, kanban, trees, caching | Production Architecture |
| Wish SSH server, Soft Serve, teatest | Infrastructure |