šŸ“š phoenix - Awesome Go Library for Command Line

Go Gopher mascot for phoenix

High-performance TUI framework with Elm-inspired architecture, perfect Unicode rendering, and zero-allocation event system

šŸ·ļø Command Line
šŸ“‚ Advanced Console UIs
⭐ 0 stars
View on GitHub šŸ”—

Detailed Description of phoenix

Phoenix TUI Framework

Phoenix TUI Framework

Go Version Release CI Go Report Card License GoDoc codecov

Multi-module monorepo - 10 independent libraries. Full metrics in CI.

Next-generation Terminal User Interface framework for Go

Organization: github.com/phoenix-tui Go Version: 1.25+

Why Phoenix?

Phoenix rises from the ashes of legacy TUI frameworks, solving critical problems:

  • Perfect Unicode/Emoji support - No more layout bugs
  • High Performance - Differential rendering, caching, zero allocations
  • DDD Architecture - Clean, testable, extendable
  • Rich Component Library - Everything you need out of the box
  • Public Cursor API - Full control for shell applications
  • Inline & Alt-Screen rendering - Per-line diffing without alt screen, or full-screen mode
  • TTY Control - Run editors, shells, and other processes from within your TUI
  • Easy Migration from Charm - Comprehensive migration guide included

Libraries

Phoenix is a modular framework with 10 independent libraries:

LibraryDescription
phoenix/coreTerminal primitives, Unicode/Emoji support (correct width calculation)
phoenix/terminalANSI terminal operations, raw mode, capabilities
phoenix/styleCSS-like styling + Theme System (presets, runtime switching)
phoenix/layoutFlexbox & grid layout (box model, responsive sizing)
phoenix/teaElm Architecture + TTY Control + Inline Renderer
phoenix/renderHigh-performance differential renderer
phoenix/componentsUI components: TextArea, TextInput, List, Viewport, Table, Modal, Progress, Select, MultiSelect, Confirm, Form
phoenix/mouseMouse events (click, scroll, drag-drop, right-click)
phoenix/clipboardCross-platform clipboard (OSC 52 for SSH)
phoenix/testingMock terminal and test utilities

Installation

Install All Libraries (Recommended for new projects)

go get github.com/phoenix-tui/phoenix@latest

This installs the umbrella module with convenient access to all Phoenix libraries through a single import:

import "github.com/phoenix-tui/phoenix"

// Use convenience API
term := phoenix.AutoDetectTerminal()
style := phoenix.NewStyle().Foreground("#00FF00").Bold()
p := phoenix.NewProgram(myModel, phoenix.WithAltScreen[MyModel]())

Install Individual Libraries (For existing projects or selective use)

go get github.com/phoenix-tui/phoenix/tea@latest        # Elm Architecture
go get github.com/phoenix-tui/phoenix/components@latest # UI Components
go get github.com/phoenix-tui/phoenix/style@latest      # Styling
go get github.com/phoenix-tui/phoenix/core@latest       # Terminal primitives

Individual imports give you more control and smaller dependencies:

import (
    tea "github.com/phoenix-tui/phoenix/tea/api"
    "github.com/phoenix-tui/phoenix/components/input/api"
)

Quick Start

Using the Umbrella Module

go get github.com/phoenix-tui/phoenix@latest
package main

import (
    "fmt"
    "os"
    "github.com/phoenix-tui/phoenix"
    tea "github.com/phoenix-tui/phoenix/tea/api"
)

type Model struct {
    count int
}

func (m Model) Init() tea.Cmd { return nil }

func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
    switch msg := msg.(type) {
    case tea.KeyMsg:
        if msg.String() == "q" {
            return m, phoenix.Quit()
        }
        m.count++
    }
    return m, nil
}

func (m Model) View() string {
    style := phoenix.NewStyle().Foreground("#00FF00").Bold()
    return style.Render(fmt.Sprintf("Count: %d\n", m.count))
}

func main() {
    p := phoenix.NewProgram(Model{}, phoenix.WithAltScreen[Model]())
    if err := p.Run(); err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
}

Using Individual Libraries

go get github.com/phoenix-tui/phoenix/tea@latest
package main

import (
    "fmt"
    "os"
    "github.com/phoenix-tui/phoenix/tea/api"
)

type Model struct {
    count int
}

func (m Model) Init() api.Cmd { return nil }

func (m Model) Update(msg api.Msg) (Model, api.Cmd) {
    switch msg := msg.(type) {
    case api.KeyMsg:
        if msg.String() == "q" {
            return m, api.Quit()
        }
        m.count++
    }
    return m, nil
}

func (m Model) View() string {
    return fmt.Sprintf("Count: %d\nPress any key to increment, 'q' to quit\n", m.count)
}

func main() {
    p := api.New(Model{}, api.WithAltScreen[Model]())
    if err := p.Run(); err != nil {
        fmt.Fprintf(os.Stderr, "Error: %v\n", err)
        os.Exit(1)
    }
}

Documentation

Key Features

1. Perfect Unicode/Emoji Support

Problem: Charm's Lipgloss has broken emoji width calculation (issue #562) Solution: Phoenix uses grapheme cluster detection with correct East Asian Width (UAX #11)

// Phoenix: CORRECT
text := "Hello šŸ‘‹ World šŸŒ"
width := style.Width(text)  // Returns 17 (correct!)

// Charm Lipgloss: BROKEN
width := lipgloss.Width(text)  // Returns 19 (wrong!)

2. High Performance

Techniques: Differential rendering, virtual buffer, caching, zero allocations on hot paths

3. DDD Architecture

library/
ā”œā”€ā”€ domain/        # Business logic (highest coverage)
ā”œā”€ā”€ application/   # Use cases
ā”œā”€ā”€ infrastructure/ # Technical details
└── api/           # Public interface

4. Public Cursor API

Problem: Bubbles TextArea has private cursor - syntax highlighting impossible Solution: Phoenix TextInput exposes CursorPosition() and ContentParts()

// Phoenix: PUBLIC API (syntax highlighting works!)
before, at, after := input.ContentParts()
highlighted := syntax.Highlight(before) +
               cursor.Render(at) +
               syntax.Highlight(after)

// Bubbles: PRIVATE (syntax highlighting impossible!)
// cursor is internal field - no access

5. TTY Control

Run external processes (vim, shells, pagers) from within your TUI:

case api.KeyMsg:
    if msg.String() == "e" {
        return m, api.ExecProcess("vim", "file.txt")
    }
case api.ExecProcessFinishedMsg:
    // Editor closed, TUI restored automatically

6. Inline Rendering

Run without alt screen - per-line diffing renders updates in place:

p := api.New(myModel) // inline mode by default - no alt screen needed

7. Mouse & Clipboard Support

Mouse: All buttons (Left, Right, Middle, Wheel), drag-drop, click detection (single/double/triple) Clipboard: Cross-platform (Windows/macOS/Linux), SSH support (OSC 52)

8. Progress Component

Progress bars and 15 animated spinner styles:

import progress "github.com/phoenix-tui/phoenix/components/progress/api"

bar := progress.NewBar(100).SetWidth(40).SetLabel("Downloading").SetValue(65)
spinner := progress.NewSpinner(progress.SpinnerDots).SetLabel("Loading")

Comparison with Charm Ecosystem

FeaturePhoenixCharm (Bubbletea/Lipgloss)
Unicode/EmojiCorrect width (UAX #11)Broken (#562)
Type SafetyGeneric constraintsinterface{} casts
Inline RenderingPer-line diffingBasic
TTY ControlExecProcess + Suspend/ResumeExecProcess only
Cursor APIPublicPrivate
ArchitectureDDD layersMonolithic
Theme SystemBuilt-in (4 presets)Manual

Contributing

Phoenix is part of an active development effort. See CONTRIBUTING.md for contribution guidelines and GoDoc for API documentation.

License

MIT License - see LICENSE file for details

Special Thanks

Professor Ancha Baranova - This project would not have been possible without her invaluable help and support. Her assistance was crucial in bringing Phoenix to life.


Rising from the ashes of legacy TUI frameworks