| name | lipgloss-v2 |
| description | Generates, explains, and debugs terminal styling and layout code using Charm's Lip Gloss v2 library for Go. Use when building styled terminal output, TUI layouts, color gradients, bordered boxes, tables, lists, or trees. Covers Style API, adaptive colors, LightDark detection, compositing layers, and all subpackages (list, table, tree). Also handles migration from Lip Gloss v1 to v2. |
Lip Gloss v2
Lip Gloss v2 (charm.land/lipgloss/v2) provides style definitions for
terminal layouts. It is a pure value type library — no global renderer, no
hidden state. Colors are downsampled at the output layer.
go get charm.land/lipgloss/v2@v2.0.0-beta.3.0.20251205162909-7869489d8971
Quick Reference
| v1 | v2 |
|---|
github.com/charmbracelet/lipgloss | charm.land/lipgloss/v2 |
type Color string | func Color(string) color.Color |
lipgloss.AdaptiveColor{...} | compat.AdaptiveColor{...} or LightDark(isDark)(light, dark) |
HasDarkBackground() | HasDarkBackground(os.Stdin, os.Stdout) |
fmt.Println(s.Render("hi")) | lipgloss.Println(s.Render("hi")) |
renderer.NewStyle() | lipgloss.NewStyle() |
See .agentsmesh/skills/lipgloss-v2/references/MIGRATION.md for the full migration guide.
Style API
Styles are immutable value types. Chain setters, end with .Render(str).
s := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#FF5F87")).
Background(lipgloss.Color("#1a1a2e")).
Padding(1, 2).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#874BFD")).
Width(40).
Align(lipgloss.Center)
lipgloss.Println(s.Render("Hello!"))
Text properties
| Method | Description |
|---|
Bold(bool) | Bold text |
Italic(bool) | Italic text |
Underline(bool) | Underline (single) |
UnderlineStyle(Underline) | UnderlineSingle/Double/Curly/Dotted/Dashed/None |
UnderlineColor(color.Color) | Color the underline separately |
Strikethrough(bool) | Strikethrough |
StrikethroughSpaces(bool) | Apply strikethrough to spaces between words |
Faint(bool) | Faint/dim text |
Blink(bool) | Blinking text |
Reverse(bool) | Reverse foreground/background |
Foreground(color.Color) | Text color |
Background(color.Color) | Background color |
Hyperlink(url, params...) | Clickable hyperlink |
Layout properties
| Method | Description |
|---|
Width(int) | Set width (pads to fill) |
Height(int) | Set height (pads to fill) |
MaxWidth(int) | Truncate at max width |
MaxHeight(int) | Truncate at max height |
Align(Position) | Horizontal text alignment |
AlignVertical(Position) | Vertical text alignment |
Inline(bool) | Render inline (no newlines) |
TabWidth(int) | Tab-to-space width (NoTabConversion to disable) |
Transform(func(string) string) | Post-render transform |
Position constants: lipgloss.Left, lipgloss.Center, lipgloss.Right,
lipgloss.Top, lipgloss.Bottom.
Padding & margin
s.Padding(1, 2)
s.Padding(1, 2, 3, 4)
s.PaddingTop(1).PaddingLeft(2)
s.PaddingChar('·')
s.Margin(1, 2)
s.MarginChar('·')
s.MarginBackground(color.Color)
Borders
s.Border(lipgloss.RoundedBorder())
s.Border(lipgloss.NormalBorder(), true)
s.Border(lipgloss.ThickBorder(), true, false)
s.BorderForeground(lipgloss.Color("#874BFD"))
s.BorderForegroundBlend(from, to)
s.BorderStyle(lipgloss.NormalBorder()).BorderBottom(true)
Border constructors: NormalBorder(), RoundedBorder(), ThickBorder(),
DoubleBorder(), BlockBorder(), HiddenBorder(), ASCIIBorder(),
MarkdownBorder(), InnerHalfBlockBorder(), OuterHalfBlockBorder().
Custom border:
b := lipgloss.Border{
Top: "─", Bottom: "─", Left: "│", Right: "│",
TopLeft: "╭", TopRight: "╮",
BottomLeft: "╰", BottomRight: "╯",
}
Style inheritance
base := lipgloss.NewStyle().Padding(0, 1).Foreground(lipgloss.Color("5"))
active := base.Bold(true).Background(lipgloss.Color("#FF5F87"))
child := lipgloss.NewStyle().Inherit(base)
Render helpers
s.Render("text")
s.String()
s.SetString("content")
Unset methods
All style properties can be unset:
s.UnsetBold()
s.UnsetForeground()
s.UnsetPadding()
s.UnsetBorder()
Color System
color.Color is the standard image/color.Color interface.
import "charm.land/lipgloss/v2"
c := lipgloss.Color("#FF5F87")
c := lipgloss.Color("200")
c := lipgloss.Red
c := lipgloss.ANSIColor(134)
c := lipgloss.NoColor{}
Adaptive colors (light/dark terminals)
Standalone:
hasDark := lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
lightDark := lipgloss.LightDark(hasDark)
fg := lightDark(lipgloss.Color("#333333"), lipgloss.Color("#f1f1f1"))
s := lipgloss.NewStyle().Foreground(fg)
Bubble Tea:
func (m model) Init() tea.Cmd {
return tea.RequestBackgroundColor
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.BackgroundColorMsg:
m.styles = newStyles(msg.IsDark())
}
return m, nil
}
func newStyles(isDark bool) styles {
ld := lipgloss.LightDark(isDark)
return styles{
title: lipgloss.NewStyle().Foreground(ld(
lipgloss.Color("#333333"),
lipgloss.Color("#f1f1f1"),
)),
}
}
Color profile selection (Complete)
import "github.com/charmbracelet/colorprofile"
p := colorprofile.Detect(os.Stdout, os.Environ())
complete := lipgloss.Complete(p)
c := complete(
lipgloss.Color("5"),
lipgloss.Color("200"),
lipgloss.Color("#ff34ac"),
)
Color manipulation
lipgloss.Darken(c, 0.2)
lipgloss.Lighten(c, 0.2)
lipgloss.Alpha(c, 0.5)
lipgloss.Complementary(c)
Color gradients
colors := lipgloss.Blend1D(40, from, to, extra...)
colors := lipgloss.Blend2D(width, height, 45.0, c1, c2, c3)
Layout Functions
row := lipgloss.JoinHorizontal(lipgloss.Top, blockA, blockB, blockC)
col := lipgloss.JoinVertical(lipgloss.Left, blockA, blockB)
out := lipgloss.Place(width, height, lipgloss.Center, lipgloss.Center, content,
lipgloss.WithWhitespaceChars("·"),
lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Foreground(subtle)),
)
lipgloss.PlaceHorizontal(width, lipgloss.Center, content)
lipgloss.PlaceVertical(height, lipgloss.Center, content)
Printing (Important!)
Always use Lip Gloss writers to ensure correct color downsampling:
lipgloss.Println(s)
lipgloss.Print(s)
lipgloss.Printf("%s\n", s)
lipgloss.Fprintln(os.Stderr, s)
lipgloss.Sprint(s)
lipgloss.Sprintf("...", s)
lipgloss.Writer = colorprofile.NewWriter(os.Stderr, os.Environ())
In Bubble Tea, downsampling is automatic — just return strings normally.
Text Utilities
w := lipgloss.Width(str)
h := lipgloss.Height(str)
w, h := lipgloss.Size(str)
wrapped := lipgloss.Wrap(str, 80, "")
out := lipgloss.StyleRunes(str, []int{0, 1, 2}, matched, unmatched)
out := lipgloss.StyleRanges(str,
lipgloss.NewRange(0, 5, boldStyle),
lipgloss.NewRange(6, 10, italicStyle),
)
Compositing (Layers)
Compose styled strings at arbitrary positions:
base := lipgloss.NewLayer(document)
modal := lipgloss.NewLayer(floatingBox).X(10).Y(5)
overlay := lipgloss.NewLayer(badge).X(80).Y(2).Z(10)
comp := lipgloss.NewCompositor(base, modal, overlay)
lipgloss.Println(comp.Render())
hit := comp.Hit(x, y)
if !hit.Empty() {
fmt.Println("Clicked layer:", hit.ID())
}
Canvas
Low-level cell buffer for manual composition:
canvas := lipgloss.NewCanvas(width, height)
canvas.Compose(layer)
result := canvas.Render()
Subpackages
list (charm.land/lipgloss/v2/list)
import "charm.land/lipgloss/v2/list"
l := list.New("Item A", "Item B", "Item C").
Enumerator(list.Roman).
EnumeratorStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1)).
ItemStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("255")))
l.Item(
list.New("Sub A", "Sub B"),
)
l.ItemStyleFunc(func(items list.Items, i int) lipgloss.Style {
if i == selected {
return selectedStyle
}
return normalStyle
})
lipgloss.Println(l)
Built-in enumerators: list.Bullet, list.Dash, list.Roman, list.Arabic,
list.Alphabet, list.Asterisk.
Custom: func(items list.Items, i int) string.
table (charm.land/lipgloss/v2/table)
import "charm.land/lipgloss/v2/table"
t := table.New().
Border(lipgloss.ThickBorder()).
BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99"))).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return lipgloss.NewStyle().Bold(true).Align(lipgloss.Center)
}
if row%2 == 0 {
return lipgloss.NewStyle().Foreground(lipgloss.Color("245"))
}
return lipgloss.NewStyle().Foreground(lipgloss.Color("241"))
}).
Headers("NAME", "LANG", "STARS").
Rows([][]string{
{"BubbleTea", "Go", "★★★★★"},
{"Lipgloss", "Go", "★★★★★"},
}...)
lipgloss.Println(t)
tree (charm.land/lipgloss/v2/tree)
import "charm.land/lipgloss/v2/tree"
t := tree.New().
Root("project/").
Child(
".git",
tree.Root("src/").
Child("main.go", "util.go"),
tree.Root("docs/").
Child("README.md"),
"go.mod",
).
Enumerator(tree.RoundedEnumerator).
EnumeratorStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99"))).
ItemStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("255")))
lipgloss.Println(t)
Integration with huh v2 Forms
Lip Gloss v2 styles power huh v2 forms. Create custom themes by implementing huh.Theme:
import (
"charm.land/huh/v2"
"charm.land/lipgloss/v2"
)
customTheme := huh.ThemeFunc(func(isDark bool) *huh.Styles {
s := &huh.Styles{}
s.Form.Base = lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#7D56F4")).
Padding(2, 4)
s.Focused.Title = lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#7D56F4"))
s.Focused.SelectSelector = lipgloss.NewStyle().
Foreground(lipgloss.Color("#FF6AD2")).
SetString("▸ ")
s.Focused.FocusedButton = lipgloss.NewStyle().
Background(lipgloss.Color("#FF6AD2")).
Foreground(lipgloss.Color("#FFFFFF")).
Padding(0, 3)
s.Blurred = s.Focused
s.Blurred.Title = s.Blurred.Title.Foreground(lipgloss.Color("#666666"))
return s
})
form := huh.NewForm(
huh.NewGroup(
huh.NewInput().Title("Name").Value(&name),
huh.NewConfirm().Title("Proceed?").Value(&ok),
),
).WithTheme(customTheme)
huh Style Structure
| Style | Purpose |
|---|
s.Form.Base | Container border/padding |
s.Focused.Title | Active field title |
s.Focused.Description | Active field help text |
s.Focused.SelectSelector | Selection indicator (▸) |
s.Focused.Option | Select/menu options |
s.Focused.FocusedButton | Active button (Confirm) |
s.Focused.TextInput.Prompt | Input prompt character |
s.Blurred.* | Inactive field styles |
s.Help.* | Keybinding help text |
See .agentsmesh/skills/lipgloss-v2/references/_examples/huh-theme.go for a complete custom theme example.
Examples Index
See .agentsmesh/skills/lipgloss-v2/references/_examples/ for runnable examples:
| File | Demonstrates |
|---|
color-standalone.go | HasDarkBackground + LightDark in standalone mode |
color-bubbletea.go | tea.BackgroundColorMsg + adaptive styles in BubbleTea |
layout.go | Full layout: tabs, title, dialog, lists, status bar, compositing |
table-languages.go | Styled table with headers, alternating rows, custom column widths |
list-grocery.go | Custom enumerator + per-item style functions |
blending-1d.go | Blend1D color gradients rendered as color bars |
compositing.go | Layer compositing with hit testing |
huh-theme.go | Custom huh form theme using Lip Gloss styles |
References
.agentsmesh/skills/lipgloss-v2/references/API.md — complete API cheat sheet
.agentsmesh/skills/lipgloss-v2/references/MIGRATION.md — v1 → v2 migration guide (also suitable for LLM-driven migration)