charm-styling
Lip Gloss v2 styling and layout patterns for Go. Use when creating or editing terminal styles, colors, borders, layouts, or visual components using Lip Gloss. Triggers on lipgloss.NewStyle, lipgloss.Color, JoinHorizontal, JoinVertical, Place, border usage, or any visual styling of terminal output.
Install
mkdir -p .claude/skills/charm-styling && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/14748" && unzip -o skill.zip -d .claude/skills/charm-styling && rm skill.zipInstalls to .claude/skills/charm-styling
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Lip Gloss v2 styling and layout patterns for Go. Use when creating or editing terminal styles, colors, borders, layouts, or visual components using Lip Gloss. Triggers on lipgloss.NewStyle, lipgloss.Color, JoinHorizontal, JoinVertical, Place, border usage, or any visual styling of terminal output.About this skill
Lip Gloss v2 Styling Patterns
Import: charm.land/lipgloss/v2
Creating Styles
Styles are value types (assignment copies). Copy() is deprecated.
style := lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#FAFAFA")).
Background(lipgloss.Color("#7D56F4")).
Padding(1, 2).
Width(40)
output := style.Render("Hello")
Every setter returns a new Style. Chain freely.
Colors (v2 Change)
Colors must use lipgloss.Color() — bare strings no longer work:
lipgloss.Color("#FF00FF") // hex -> TrueColor
lipgloss.Color("205") // ANSI 256
lipgloss.Color("1") // ANSI 16
lipgloss.NoColor{} // transparent
Named constants: lipgloss.Red, lipgloss.Green, lipgloss.BrightCyan, etc.
Dark/Light Background (v2 Change)
AdaptiveColor is removed. Use LightDark:
hasDark := lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
lightDark := lipgloss.LightDark(hasDark)
fg := lightDark(lipgloss.Color("#333"), lipgloss.Color("#ccc"))
In BubbleTea: handle tea.BackgroundColorMsg on startup for detection.
Printing (v2 Change — Critical)
v2 does NOT auto-downsample colors. Outside BubbleTea, use lipgloss print functions:
lipgloss.Println(style.Render("text")) // auto-downsamples
lipgloss.Printf("Status: %s\n", styled)
lipgloss.Sprint(styled) // returns downsampled string
Inside BubbleTea, rendering handles downsampling automatically.
Layout
// Side by side
lipgloss.JoinHorizontal(lipgloss.Top, left, right)
lipgloss.JoinHorizontal(lipgloss.Center, col1, col2, col3)
// Stacked
lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
lipgloss.JoinVertical(lipgloss.Center, title, content)
// Place in a box
lipgloss.Place(80, 24, lipgloss.Center, lipgloss.Center, content)
lipgloss.PlaceHorizontal(80, lipgloss.Right, text)
lipgloss.PlaceVertical(24, lipgloss.Bottom, text)
Position values: lipgloss.Top, lipgloss.Bottom, lipgloss.Left, lipgloss.Right, lipgloss.Center.
Borders
style := lipgloss.NewStyle().
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("#874BFD")).
Padding(1, 2)
Built-in borders: NormalBorder(), RoundedBorder(), ThickBorder(), DoubleBorder(), BlockBorder(), HiddenBorder(), ASCIIBorder().
Per-side control:
.BorderTop(true).BorderBottom(true).BorderLeft(false).BorderRight(false)
.BorderTopForeground(lipgloss.Color("#F00"))
Dimensions
.Width(40) // min width (pads with spaces)
.Height(10) // min height (pads with newlines)
.MaxWidth(80) // truncates/wraps
.MaxHeight(20) // truncates
Padding and Margin (CSS-like)
.Padding(1) // all sides
.Padding(1, 2) // top/bottom, left/right
.Padding(1, 2, 3, 4) // top, right, bottom, left (clockwise)
.PaddingLeft(4) // individual side
.Margin(1, 2)
.MarginBackground(lipgloss.Color("#333"))
Frame Size Helpers
hFrame := style.GetHorizontalFrameSize() // border + padding + margin
vFrame := style.GetVerticalFrameSize()
// Responsive content width:
contentWidth := windowWidth - hFrame
Text Measurement
w := lipgloss.Width(rendered) // ANSI-aware cell width
h := lipgloss.Height(rendered)
w, h := lipgloss.Size(rendered)
New v2 Features
Hyperlinks:
.Hyperlink("https://example.com")
Underline styles:
.UnderlineStyle(lipgloss.UnderlineCurly)
.UnderlineColor(lipgloss.Color("#FF0000"))
Color manipulation:
lipgloss.Darken(c, 0.2)
lipgloss.Lighten(c, 0.3)
lipgloss.Complementary(c)
Gradients:
lipgloss.Blend1D(steps, color1, color2, color3)
Style ranges:
lipgloss.StyleRanges(text,
lipgloss.NewRange(0, 5, boldStyle),
lipgloss.NewRange(6, 11, dimStyle),
)
Table, List, Tree
import "charm.land/lipgloss/v2/table"
import "charm.land/lipgloss/v2/list"
import "charm.land/lipgloss/v2/tree"
Table:
t := table.New().
Headers("Name", "Status").
Row("prod-01", "running").
Row("prod-02", "stopped").
Border(lipgloss.RoundedBorder()).
Width(60).
StyleFunc(func(row, col int) lipgloss.Style {
if row == table.HeaderRow {
return lipgloss.NewStyle().Bold(true)
}
return lipgloss.NewStyle()
})
fmt.Println(t.Render())
List:
l := list.New("Item 1", "Item 2", "Item 3").
Enumerator(list.Bullet)
Tree:
t := tree.Root("Root").
Child("Foo", tree.Root("Bar").Child("Baz"))
Style Organization Pattern
Keep styles in a dedicated file (e.g., styles.go):
package tui
var (
titleStyle = lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#FAFAFA")).
MarginBottom(1)
errorStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#FF0000"))
subtleStyle = lipgloss.NewStyle().
Foreground(lipgloss.Color("#666666"))
)
Do NOT scatter style definitions across View functions. Centralize them for consistency.
Common Mistakes to Avoid
- Do NOT use bare color strings —
lipgloss.Color("#fff")not"#fff" - Do NOT use
fmt.Printlnwith styled output outside BubbleTea — uselipgloss.Println - Do NOT use
style.Copy()— just assign:newStyle := style.Bold(true) - Do NOT use
AdaptiveColor— it's removed in v2, useLightDark - Do NOT hardcode widths — use
WindowSizeMsgand compute responsive sizes