Proposal: Unified theming system across charmbracelet libraries
Author: junhinhowCreated Mar 31, 2026Updated Aug 14, 2026
Problem
Each charmbracelet library has its own styling system:
- lipgloss uses
lipgloss.Stylewith inline color definitions - glamour uses
StyleConfigwith JSON or Go structs - bubbles components each have their own
Stylesstruct
When building a TUI app, you end up defining the same colors 3+ times in different formats. Changing your theme means updating every single style definition across libraries.
Proposed Solution
A cross-library theming package that defines semantic color palettes once, then derives styles for any charmbracelet library.
import themes "github.com/junhinhow/charm-themes"
// Pick a theme
theme := themes.Gruvbox
// Use with lipgloss — pre-built semantic styles
styles := theme.Lipgloss()
fmt.Println(styles.Title.Render("Hello"))
fmt.Println(styles.Error.Render("Something went wrong"))
fmt.Println(styles.Border.Render("Boxed content"))
// Or use colors directly in custom styles
myStyle := lipgloss.NewStyle().
Foreground(theme.Primary).
Background(theme.Background)Theme Structure
type Theme struct {
Name string
Background color.Color
Foreground color.Color
Primary color.Color // headings, titles
Secondary color.Color // subtitles, secondary info
Accent color.Color // highlights, emphasis
Success color.Color // green/positive
Warning color.Color // yellow/caution
Error color.Color // red/negative
Info color.Color // blue/informational
Muted color.Color // gray/disabled
Syntax SyntaxColors // code highlighting colors
}Built-in Themes
| Theme | Background | Primary | Accent |
|---|---|---|---|
| Gruvbox | #282828 |
#fabd2f |
#83a598 |
| Dracula | #282a36 |
#bd93f9 |
#ff79c6 |
| Nord | #2e3440 |
#88c0d0 |
#b48ead |
| Catppuccin | #1e1e2e |
#cba6f7 |
#f5c2e7 |
| Tokyo Night | #1a1b26 |
#7aa2f7 |
#bb9af7 |
POC Repository
I've built a working proof-of-concept with lipgloss integration: https://github.com/junhinhow/charm-themes
Currently supports:
- 5 built-in themes with complete palettes
theme.Lipgloss()→ pre-builtLipglossStyles(Base, Bold, Title, Error, Border, Code, etc.)- Direct access to semantic
color.Colorvalues for custom styles
Roadmap (if there's interest)
-
theme.Glamour()→ convert toglamour.StyleConfig+ Chroma palette -
theme.Bubbles()→ pre-built styles for table, list, textinput, etc. -
theme.Huh()→ form theme integration - Light/dark variant detection via
lipgloss.HasDarkBackground() - Custom theme loading from JSON/YAML
Questions for the team
- Would this be useful as an official charmbracelet package (e.g.
charm.land/themes)? - Or better as a community package that integrates with the ecosystem?
- Any feedback on the
Themestruct design — are the semantic color roles sufficient?
Happy to adapt the approach based on your feedback. This came from the experience of building apps with the full Charm stack and repeatedly copy-pasting color values across lipgloss, glamour, and bubbles configs.
Source: charmbracelet/lipgloss