charmbracelet/bubbles
TUI components for Bubble Tea π«§
Healthy across the board
weakest axisPermissive license, no critical CVEs, actively maintained β safe to depend on.
Has a license, tests, and CI β clean foundation to fork and modify.
Documented and popular β useful reference codebase to read through.
No critical CVEs, sane security posture β runnable as-is.
- βLast commit 2w ago
- β16 active contributors
- βDistributed ownership (top contributor 27% of recent commits)
Show all 6 evidence items βShow less
- βMIT licensed
- βCI configured
- βTests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README β live-updates from the latest cached analysis.
[](https://repopilot.app/r/charmbracelet/bubbles)Paste at the top of your README.md β renders inline like a shields.io badge.
βΈPreview social card (1200Γ630)
This card auto-renders when someone shares https://repopilot.app/r/charmbracelet/bubbles on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: charmbracelet/bubbles
Generated by RepoPilot Β· 2026-05-09 Β· Source
π€Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale β STOP and ask the user to regenerate it before proceeding. - Treat the AI Β· unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/charmbracelet/bubbles shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything β but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
π―Verdict
GO β Healthy across the board
- Last commit 2w ago
- 16 active contributors
- Distributed ownership (top contributor 27% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
β Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live charmbracelet/bubbles
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale β regenerate it at
repopilot.app/r/charmbracelet/bubbles.
What it runs against: a local clone of charmbracelet/bubbles β the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in charmbracelet/bubbles | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit β€ 42 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of charmbracelet/bubbles. If you don't
# have one yet, run these first:
#
# git clone https://github.com/charmbracelet/bubbles.git
# cd bubbles
#
# Then paste this script. Every check is read-only β no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of charmbracelet/bubbles and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "charmbracelet/bubbles(\\.git)?\\b" \\
&& ok "origin remote is charmbracelet/bubbles" \\
|| miss "origin remote is not charmbracelet/bubbles (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift β was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "bubbles.go" \\
&& ok "bubbles.go" \\
|| miss "missing critical file: bubbles.go"
test -f "go.mod" \\
&& ok "go.mod" \\
|| miss "missing critical file: go.mod"
test -f "list/list.go" \\
&& ok "list/list.go" \\
|| miss "missing critical file: list/list.go"
test -f "viewport/keymap.go" \\
&& ok "viewport/keymap.go" \\
|| miss "missing critical file: viewport/keymap.go"
test -f "textinput/textinput.go" \\
&& ok "textinput/textinput.go" \\
|| miss "missing critical file: textinput/textinput.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 42 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~12d)"
else
miss "last commit was $days_since_last days ago β artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) β safe to trust"
else
echo "artifact has $fail stale claim(s) β regenerate at https://repopilot.app/r/charmbracelet/bubbles"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
β‘TL;DR
Bubbles is a Go library providing reusable TUI (Terminal User Interface) components for Bubble Tea applications. It includes 10+ primitives like text input, text area, table, list, spinner, paginator, and file picker that handle keyboard/mouse input and rendering, eliminating the need to build common UI patterns from scratch in terminal applications. Flat package structure: each component (cursor/, filepicker/, help/, list/, paginator/, progress/, textinput/, textarea/, table/, spinner/) is a standalone subdirectory with its own .go files and tests. Internal utilities live in internal/ (memoization, runeutil, wordwrap). Minimal organizational hierarchy reflects the modular, independent nature of each UI primitive.
π₯Who it's for
Go developers building interactive command-line applications with Bubble Tea who need production-ready UI components (text fields, tables, file selection) without implementing input handling and rendering logic themselves. Used in production by tools like Crush and many other CLI applications in the Charm ecosystem.
π±Maturity & risk
Production-ready and actively maintained. The project has graduated to v2 (with an UPGRADE_GUIDE_V2.md), maintains comprehensive CI/CD workflows (build.yml, coverage.yml, lint.yml, release.yml), includes test coverage for components, and uses golangci linter. Go 1.25.0 minimum requirement indicates modern maintenance standards.
Low risk for a stable component library. Dependencies are well-curated (lipgloss v2, bubbletea v2, harmonica) from the same Charm ecosystem with active maintenance. The monolithic single-package structure reduces versioning complexity. However, it's highly specialized (Bubble Tea-only) so adoption is constrained to that ecosystem, and breaking changes between v1βv2 indicate occasional API churn.
Active areas of work
Active v2 development with Go 1.25.0 support. Recent work likely involves refinements to v2 API (UPGRADE_GUIDE_V2.md exists, suggesting post-v1 stabilization). Dependabot integration suggests continuous dependency updates. CI workflows (build.yml, lint.yml, coverage.yml) are configured and running, indicating ongoing testing and quality maintenance.
πGet running
git clone https://github.com/charmbracelet/bubbles.git
cd bubbles
go mod download
go test ./...
Daily commands:
No 'run' in traditional senseβthis is a library. Run tests with go test ./... or go test ./list -v. Build example binaries using go build against consumer applications that import bubbles (see bubbletea examples repository).
πΊοΈMap of the codebase
bubbles.goβ Package entry point that exports all bubble components; defines the public API contract every contributor must understandgo.modβ Defines all dependencies including Bubble Tea framework and Lipgloss styling library; critical for understanding integration pointslist/list.goβ Core list component implementation; one of the most feature-rich and heavily-used components in the libraryviewport/keymap.goβ Demonstrates the keybinding pattern used across multiple components for consistent keyboard handlingtextinput/textinput.goβ Text input component showing state management patterns, cursor handling, and form-input patternstable/table.goβ Table component with complex layout and rendering logic; illustrates viewport integration and multi-column handlingprogress/progress.goβ Progress bar with color blending and animation logic; demonstrates rendering complexity and styling patterns
π οΈHow to make changes
Add a New UI Component
- Create new directory under repo root (e.g., mycomponent/) with mycomponent.go (
mycomponent/mycomponent.go) - Implement Model interface with Update(msg tea.Msg) tea.Model and View() string methods (
mycomponent/mycomponent.go) - Add optional styles.go for Lipgloss styling configuration if component needs theme support (
mycomponent/styles.go) - Add keybindings and keymap file similar to viewport/keymap.go for keyboard navigation (
mycomponent/keymap.go) - Create mycomponent_test.go with golden file tests in testdata/TestModel_View directory (
mycomponent/mycomponent_test.go) - Export component constructor from bubbles.go root package (
bubbles.go)
Add String Rendering or Width Calculation Logic
- Import and use internal/runeutil for rune width calculations to handle multi-byte characters correctly (
internal/runeutil/runeutil.go) - Use github.com/mattn/go-runewidth and github.com/rivo/uniseg for terminal-aware string operations (
go.mod) - Add memoization via internal/memoization for expensive width or layout calculations if called frequently (
internal/memoization/memoization.go)
Add Golden File Regression Tests
- Create testdata/TestMyFeature/ directory in component package (
mycomponent/testdata/TestMyFeature) - Write test using github.com/charmbracelet/x/exp/golden package to capture View() output (
mycomponent/mycomponent_test.go) - Run tests with -update flag to generate .golden files for reference snapshots (
mycomponent/testdata/TestMyFeature/scenario_name.golden)
Enhance Keyboard Navigation
- Define KeyMap struct with tea.KeyBinding fields following pattern in viewport/keymap.go (
mycomponent/keymap.go) - Parse key messages in Update() method using key/key.go utilities (
key/key.go) - Call tea.Cmd functions (tea.Quit, tea.Batch, etc.) to emit Bubble Tea commands based on key input (
mycomponent/mycomponent.go)
π§Why these technologies
- Bubble Tea framework (bubbletea/v2) β Provides the Model-Update-View architecture and event loop; essential TUI framework this library builds upon
- Lipgloss (lipgloss/v2) β Handles terminal styling (colors, borders, padding, alignment); decouples style definitions from rendering logic
- go-runewidth (mattn/go-runewidth) β Correctly calculates display width of Unicode characters; essential for proper text layout in terminal
- uniseg (rivo/uniseg) β Provides grapheme cluster segmentation for accurate text boundaries; supports emoji and combining characters
- Golden file testing (charmbracelet/x/exp/golden) β Enables regression testing of terminal output; captures visual correctness across layout changes
βοΈTrade-offs already made
-
Synchronous component model with optional Cmd-based async operations
- Why: Simplifies component state management and composability; Bubble Tea handles async scheduling
- Consequence: Components cannot block during Update/View; long operations must be wrapped in Cmd
-
Styling via Lipgloss objects rather than embedded style strings
- Why: Enables theme consistency, reusability, and decoupling of logic from presentation
- Consequence: Components require Lipgloss knowledge; styling adds memory overhead for style objects
-
Golden file tests for rendering validation
- Why: Provides pixel-perfect regression testing for terminal output; catches visual regressions automatically
- Consequence: Snapshot updates can mask unintended visual changes; requires careful review of -update diffs
-
Per-component package structure (list/, textarea/, etc.)
- Why: Enables independent versioning, selective imports, and isolated testing
- Consequence: Shared logic must live in internal/ or be duplicated; encourages internal utilities growth
π«Non-goals (don't propose these)
- Does not handle network I/O directly; integrates with Bubble Tea's async Cmd system for external operations
- Does not manage application state globally; components are self-contained and composed by parent applications
- Not a complete TUI framework; provides reusable primitives only; application structure responsibility belongs to Bubble Tea and user code
- Does not provide WebAssembly/browser rendering; terminal-only; requires text-based terminal emulator
- Does not include accessibility features like screen reader integration; pure terminal/ANSI output
πͺ€Traps & gotchas
No required environment variables or external services. Key constraint: strict Bubble Tea v2 dependency (charm.land/bubbletea/v2) means components only work with Bubble Tea applications, not standalone. Unicode handling is non-trivial: runeutil/wordwrap behavior differs by width calculation (mattn/go-runewidth + clipperhouse/displaywidth); verify text display on your platform. File picker (filepicker/) has platform-specific hidden file handling (hidden_unix.go vs hidden_windows.go) requiring OS-specific testing. Test golden files in help/testdata/ must be regenerated if output formatting changes.
ποΈArchitecture
πRelated repos
charmbracelet/bubbleteaβ Core dependency and framework that bubbles components build on top of; all components implement Bubble Tea's Model interfacecharmbracelet/lipglossβ Styling library used by all bubbles components for colors, borders, padding; tight integration for consistent TUI appearancecharmbracelet/huhβ Higher-level form/prompt library built on top of bubbles components; alternative if you need form workflows instead of individual primitivescharmbracelet/harmonicaβ Animation library used by bubbles for smooth transitions and effects in spinners and progress indicatorscharmbracelet/xβ Experimental utilities (ansi, golden testing, term) used internally by bubbles for ANSI handling and test fixtures
πͺPR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive tests for stopwatch/stopwatch.go
The stopwatch package lacks a test file (stopwatch/stopwatch_test.go is missing), unlike other components (spinner, paginator, progress, list, table, etc.) which all have test coverage. This is a high-value addition that would improve reliability and serve as a reference implementation for testing timer-based TUI components.
- [ ] Create stopwatch/stopwatch_test.go
- [ ] Add unit tests for Start(), Stop(), Reset(), and Elapsed() methods
- [ ] Add tests for pause/resume functionality if available
- [ ] Add tests for edge cases (stopping before starting, multiple resets, elapsed time accuracy)
- [ ] Ensure test coverage aligns with other components in the repo (spinner, paginator)
Add README.md documentation for cursor, key, and paginator packages
Most packages like list/ and help/ have README.md files with usage examples, but cursor/, key/, and paginator/ are missing them. This inconsistency makes it harder for new contributors and users to understand the API. Since these are foundational components, adding READMEs would significantly improve discoverability.
- [ ] Create cursor/README.md with cursor movement examples and API overview
- [ ] Create key/README.md documenting key binding utilities and key matching patterns
- [ ] Create paginator/README.md with pagination examples and configuration options
- [ ] Include code examples showing typical usage patterns for each component
- [ ] Reference these READMEs from the main bubbles.go or root README.md
Add golden file tests for filepicker component
The filepicker package (filepicker/filepicker.go) lacks test data and golden file tests, unlike progress/ and table/ which have comprehensive testdata/ directories. Given that filepicker has platform-specific code (hidden_unix.go, hidden_windows.go), adding golden tests would ensure consistent rendering across platforms and catch regressions in the UI output.
- [ ] Create filepicker/testdata directory structure (following progress/testdata and table/testdata patterns)
- [ ] Add golden file tests for different filepicker states (empty directory, files with hidden items, etc.)
- [ ] Create platform-specific test cases for hidden file visibility on Unix vs Windows
- [ ] Create filepicker/filepicker_test.go if missing, using the golden testing pattern from other components
- [ ] Test keyboard navigation and selection rendering in golden outputs
πΏGood first issues
- Add tests to spinner/spinner_test.go and progress/progress.goβno test files exist yet for these components despite them being in examples; write basic Update/View tests following the pattern in list/list_test.go
- Add cross-platform integration tests for filepicker/ beyond hidden file handling; verify file picker navigates correctly on Windows/Unix with symlinks and permission-denied directories
- Extend internal/wordwrap/ documentation with examples of how list/list.go and textarea/textarea.go use it; currently underdocumented for new contributors trying to understand text layout
βTop contributors
Click to expand
Top contributors
- @aymanbagabas β 27 commits
- @dependabot[bot] β 22 commits
- @meowgorithm β 18 commits
- @andreynering β 7 commits
- @caarlos0 β 7 commits
πRecent commits
Click to expand
Recent commits
ef0090eβ chore: remove CODEOWNERS (andreynering)6feda24β chore(deps): bump the all group with 3 updates (#958) (dependabot[bot])42130e8β chore(deps): bump github.com/mattn/go-runewidth in the all group (#952) (dependabot[bot])0d62ce2β chore(deps): bump dependabot/fetch-metadata from 2 to 3 in the all group (#953) (dependabot[bot])204774bβ chore(deps): bump github.com/mattn/go-runewidth in the all group (#945) (dependabot[bot])a13f110β docs: fix typo in README (#921) (Rohan5commit)f1daacfβ feat(textarea): dynamic height (#910) (meowgorithm)d2b804eβ chore(deps): bump the all group with 2 updates (#908) (dependabot[bot])c2c79e3β chore(deps): bump the all group with 2 updates (#902) (dependabot[bot])8d9107fβ chore: bump bubbletea and lipgloss to v2.0.0 (aymanbagabas)
πSecurity observations
The charmbracelet/bubbles codebase demonstrates generally good security practices as a TUI component library. No critical vulnerabilities were identified. Primary concerns are: (1) the unusual Go version specification requiring verification, (2) clipboard access functionality that should be carefully controlled, (3) fuzzy matching operations that need input validation and DoS protection, (4) file picker path handling requiring proper sanitization, and (5) text input processing needing escape sequence validation. The codebase lacks hardcoded secrets and doesn't appear to have SQL injection or traditional web vulnerabilities. Recommend conducting regular dependency audits and implementing input validation across user-facing components.
- Medium Β· Outdated Go Version β
go.mod. The project specifies Go 1.25.0 in go.mod, which appears to be a future or non-standard version. This may indicate a configuration error or use of an unstable Go release, which could introduce compatibility issues or security vulnerabilities. Fix: Use a stable, widely-supported Go version (e.g., 1.22.x or 1.23.x). Verify the intended Go version and update go.mod accordingly. - Low Β· Clipboard Dependency Risk β
go.mod - github.com/atotto/clipboard v0.1.4. The package 'github.com/atotto/clipboard' provides system clipboard access. This functionality could potentially be exploited to read sensitive data from or write malicious data to the system clipboard, especially in multi-user environments. Fix: Review how clipboard functionality is used within the codebase. Ensure clipboard operations are properly validated and that users are informed when clipboard access occurs. Consider sandboxing or restricting clipboard access. - Low Β· Fuzzy Matching Library β
go.mod - github.com/sahilm/fuzzy v0.1.1. The 'github.com/sahilm/fuzzy' dependency performs fuzzy string matching. If used on untrusted input without proper validation, this could potentially be exploited for ReDoS (Regular Expression Denial of Service) attacks or for information disclosure through pattern matching. Fix: Validate and sanitize input before passing to fuzzy matching functions. Implement timeouts or resource limits on fuzzy matching operations to prevent denial of service. - Low Β· File Picker Component Security β
filepicker/. The filepicker component has platform-specific hidden file handling (hidden_unix.go, hidden_windows.go). Improper implementation could expose sensitive files or allow directory traversal attacks. Fix: Review file picker implementation to ensure proper path sanitization, prevention of directory traversal (../ sequences), and correct handling of hidden files across platforms. Implement whitelist-based path validation. - Low Β· Text Input Component XSS-like Risks β
textarea/textarea.go, textinput/. The textarea and textinput components process user input. While Go doesn't have traditional XSS, improper handling of special characters or ANSI escape sequences could lead to terminal injection or unexpected behavior. Fix: Ensure all user input is properly escaped when rendered to the terminal. Validate and sanitize ANSI escape sequences and special characters to prevent terminal injection attacks.
LLM-derived; treat as a starting point, not a security audit.
πWhere to read next
- Open issues β current backlog
- Recent PRs β what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals β see the live page for receipts. Re-run on a new commit to refresh.