← スキル一覧に戻る
1. Style Definitions (
2. Table Model (

go-tui-with-bubble-tea
by hoangtran1411
⭐ 1🍴 1📅 2026年1月25日
SKILL.md
name: Go TUI with Bubble Tea description: Build beautiful, interactive terminal user interfaces in Go using Charmbracelet's Bubble Tea framework with Lipgloss styling.
Go TUI with Bubble Tea
This skill provides patterns for creating premium terminal user interfaces using charmbracelet/bubbletea, bubbles, and lipgloss.
When to Use
- Interactive CLI applications requiring navigation
- Real-time data displays with refresh capability
- Form inputs and selection interfaces
- Applications needing visual appeal in terminal
Dependencies
go get github.com/charmbracelet/bubbletea
go get github.com/charmbracelet/bubbles
go get github.com/charmbracelet/lipgloss
Architecture Pattern
ui/
├── table.go # Table-based interfaces
├── form.go # Form inputs
├── styles.go # Lipgloss style definitions
└── messages.go # Custom tea.Msg types
Core Templates
1. Style Definitions (ui/styles.go)
package ui
import "github.com/charmbracelet/lipgloss"
var (
// Base container styles
baseStyle = lipgloss.NewStyle().
BorderStyle(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("240"))
// Header style
headerStyle = lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("205")).
Background(lipgloss.Color("235")).
Padding(0, 1)
// Selection highlight
selectedStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("229")).
Background(lipgloss.Color("57")).
Bold(true)
// Title style
titleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("205")).
Background(lipgloss.Color("235")).
Bold(true).
Padding(0, 1).
MarginBottom(1)
// Help text style
helpStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("241")).
MarginTop(1)
// Status styles
successStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("46")).
Bold(true)
errorStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("196")).
Bold(true)
warningStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("226")).
Bold(true)
)
2. Table Model (ui/table.go)
package ui
import (
"fmt"
"strings"
"github.com/charmbracelet/bubbles/table"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
)
// Custom message types
type itemsMsg []Item
type errMsg struct{ err error }
func (e errMsg) Error() string { return e.err.Error() }
// Item represents a row in the table
type Item struct {
ID int
Name string
Status string
// Add more fields as needed
}
// Model is the Bubble Tea model for our TUI
type Model struct {
table table.Model
items []Item
message string
err error
}
// NewModel creates a new TUI model
func NewModel() Model {
columns := []table.Column{
{Title: "ID", Width: 5},
{Title: "Name", Width: 30},
{Title: "Status", Width: 15},
}
t := table.New(
table.WithColumns(columns),
table.WithFocused(true),
table.WithHeight(15),
)
// Apply styles
s := table.DefaultStyles()
s.Header = headerStyle
s.Selected = selectedStyle
t.SetStyles(s)
return Model{
table: t,
}
}
// Init initializes the model
func (m Model) Init() tea.Cmd {
return m.loadItems
}
// loadItems is a command that loads items
func (m Model) loadItems() tea.Msg {
// Replace with your data loading logic
items := []Item{
{ID: 1, Name: "Item 1", Status: "Active"},
{ID: 2, Name: "Item 2", Status: "Inactive"},
}
return itemsMsg(items)
}
// Update handles messages and updates the model
func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c", "esc":
return m, tea.Quit
case "r":
m.message = "Refreshing..."
return m, m.loadItems
case "enter":
if len(m.items) > 0 && m.table.Cursor() < len(m.items) {
selected := m.items[m.table.Cursor()]
m.message = fmt.Sprintf("Selected: %s", selected.Name)
}
}
case itemsMsg:
m.items = msg
m.updateTable()
m.message = "Items loaded!"
return m, nil
case errMsg:
m.err = msg.err
m.message = fmt.Sprintf("Error: %v", msg.err)
return m, nil
}
m.table, cmd = m.table.Update(msg)
return m, cmd
}
// updateTable updates the table rows from items
func (m *Model) updateTable() {
rows := []table.Row{}
for _, item := range m.items {
status := item.Status
switch status {
case "Active":
status = successStyle.Render(status)
case "Inactive":
status = errorStyle.Render(status)
default:
status = warningStyle.Render(status)
}
rows = append(rows, table.Row{
fmt.Sprintf("%d", item.ID),
item.Name,
status,
})
}
m.table.SetRows(rows)
}
// View renders the TUI
func (m Model) View() string {
var b strings.Builder
// Title
title := titleStyle.Render("🚀 My Application")
b.WriteString(title)
b.WriteString("\n\n")
// Table
b.WriteString(baseStyle.Render(m.table.View()))
b.WriteString("\n")
// Message
if m.message != "" {
b.WriteString("\n")
if m.err != nil {
b.WriteString(errorStyle.Render(m.message))
} else {
b.WriteString(successStyle.Render(m.message))
}
b.WriteString("\n")
}
// Help
help := helpStyle.Render(
"↑/↓: Navigate • Enter: Select • r: Refresh • q: Quit",
)
b.WriteString("\n")
b.WriteString(help)
return b.String()
}
3. Running the TUI
package main
import (
"fmt"
"os"
tea "github.com/charmbracelet/bubbletea"
"yourapp/ui"
)
func main() {
p := tea.NewProgram(ui.NewModel())
if _, err := p.Run(); err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
}
Color Reference
Common Lipgloss Colors
| Code | Color | Use Case |
|---|---|---|
46 | Green | Success, Running |
196 | Red | Error, Stopped |
226 | Yellow | Warning, Pending |
205 | Pink | Accent, Headers |
229 | Light Yellow | Selected |
57 | Purple | Selection Background |
240 | Gray | Borders |
241 | Light Gray | Help text |
235 | Dark Gray | Background |
Best Practices
-
Separate styles: Keep style definitions in a separate file for maintainability
-
Use the Elm Architecture:
Model- Application stateUpdate- Handle messages, return new model + commandsView- Render the model to a string
-
Async operations as Commands: Return
tea.Cmdfor async operationsfunc (m Model) doAsyncTask() tea.Cmd { return func() tea.Msg { result, err := asyncOperation() if err != nil { return errMsg{err} } return resultMsg(result) } } -
Handle window resize:
case tea.WindowSizeMsg: m.width = msg.Width m.height = msg.Height -
Use consistent keybindings:
q/Esc/Ctrl+C- Quitr- RefreshEnter- Select/Confirm↑/↓orj/k- Navigate
-
Provide visual feedback for all actions
Integration with CLI
To launch TUI when no subcommand is provided:
// In cmd/root.go
var rootCmd = &cobra.Command{
Use: "app",
Short: "My app",
Run: func(cmd *cobra.Command, args []string) {
// Launch TUI when no subcommand
p := tea.NewProgram(ui.NewModel())
if _, err := p.Run(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
},
}
スコア
総合スコア
60/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
✓LICENSE
ライセンスが設定されている
+10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です