Problem
Each charmbracelet library has its own styling system:
- lipgloss uses
lipgloss.Style with inline color definitions
- glamour uses
StyleConfig with JSON or Go structs
- bubbles components each have their own
Styles struct
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-built LipglossStyles (Base, Bold, Title, Error, Border, Code, etc.)
- Direct access to semantic
color.Color values for custom styles
Roadmap (if there's interest)
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
Theme struct 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.
Problem
Each charmbracelet library has its own styling system:
lipgloss.Stylewith inline color definitionsStyleConfigwith JSON or Go structsStylesstructWhen 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.
Theme Structure
Built-in Themes
#282828#fabd2f#83a598#282a36#bd93f9#ff79c6#2e3440#88c0d0#b48ead#1e1e2e#cba6f7#f5c2e7#1a1b26#7aa2f7#bb9af7POC Repository
I've built a working proof-of-concept with lipgloss integration:
👉 https://github.com/junhinhow/charm-themes
Currently supports:
theme.Lipgloss()→ pre-builtLipglossStyles(Base, Bold, Title, Error, Border, Code, etc.)color.Colorvalues for custom stylesRoadmap (if there's interest)
theme.Glamour()→ convert toglamour.StyleConfig+ Chroma palettetheme.Bubbles()→ pre-built styles for table, list, textinput, etc.theme.Huh()→ form theme integrationlipgloss.HasDarkBackground()Questions for the team
charm.land/themes)?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.