1---
2name: charm-lipgloss
3description: "CSS-like terminal styling for Go with lipgloss v2 - styles, colors, borders, layout, tables, lists, and trees. Use when styling Go terminal output, lipgloss, terminal layout composition, or building styled tables/lists/trees in Go."
4---
5
6# Lip Gloss v2
7
8CSS-like terminal styling for Go. Import: `charm.land/lipgloss/v2`
9
10v1 (`github.com/charmbracelet/lipgloss`) is deprecated. See `references/v1-to-v2-migration.md`.
11
12## Quick Start
13
14```go
15package main
16
17import "charm.land/lipgloss/v2"
18
19func main() {
20 style := lipgloss.NewStyle().
21 Bold(true).
22 Foreground(lipgloss.Color("#FAFAFA")).
23 Background(lipgloss.Color("#7D56F4")).
24 Padding(1, 2).
25 Width(30)
26
27 lipgloss.Println(style.Render("Hello, terminal!"))
28}
29```
30
31Rules:
32- Use `lipgloss.Println` not `fmt.Println` for automatic color downsampling
33- `Style` is a value type. Assignment copies. No renderer, no pointers.
34- `lipgloss.Color()` is a function returning `color.Color`, not a type
35
36## Core API Reference
37
38### Style
39
40Create: `lipgloss.NewStyle()`. All methods return new `Style` (immutable).
41
42```go
43s := lipgloss.NewStyle().
44 Bold(true).Italic(true).Faint(true).Strikethrough(true).Reverse(true).Blink(true).
45 Underline(true). // or UnderlineStyle(lipgloss.UnderlineCurly)
46 UnderlineColor(lipgloss.Color("#FF0000")).
47 Foreground(lipgloss.Color("#FF0000")).
48 Background(lipgloss.Color("63")).
49 Width(40).Height(10).MaxWidth(80).MaxHeight(20).
50 Align(lipgloss.Center). // horizontal; or Align(hPos, vPos)
51 Padding(1, 2).PaddingChar('.'). // CSS shorthand: 1-4 args
52 Margin(1, 2).MarginBackground(c). // same shorthand as padding
53 Border(lipgloss.RoundedBorder()).
54 BorderForeground(lipgloss.Color("63")).
55 Inline(true). // single line, no block formatting
56 Transform(strings.ToUpper).
57 Hyperlink("https://example.com")
58
59output := s.Render("text", "more") // renders with style applied
60```
61
62Position constants: `Left`/`Top` (0.0), `Center` (0.5), `Right`/`Bottom` (1.0).
63
64Padding/Margin shorthand follows CSS: 1 arg = all, 2 = vert/horiz, 3 = top/horiz/bottom, 4 = clockwise.
65
66Underline styles: `UnderlineNone`, `UnderlineSingle`, `UnderlineDouble`, `UnderlineCurly`, `UnderlineDotted`, `UnderlineDashed`.
67
68Inheritance: `child.Inherit(parent)` copies unset rules. Margins/padding are NOT inherited.
69
70Copying: `copy := style` (value type). `.Copy()` is deprecated.
71
72Getters/Unsetters: every property has `Get*()` and `Unset*()` variants. Key sizing getters: `GetHorizontalFrameSize()`, `GetVerticalFrameSize()` (border + margin + padding). See `references/api-details.md`.
73
74### Color
75
76All implement `image/color.Color`.
77
78```go
79lipgloss.Color("#FF0000") // hex TrueColor
80lipgloss.Color("#F00") // short hex
81lipgloss.Color("21") // ANSI256
82lipgloss.Color("5") // ANSI 16
83lipgloss.Magenta // named constant (ansi.BasicColor)
84lipgloss.NoColor{} // absence of color
85lipgloss.RGBColor{R: 255} // direct RGB
86lipgloss.ANSIColor(134) // ANSI256 by number
87```
88
89Named ANSI 16: `Black`, `Red`, `Green`, `Yellow`, `Blue`, `Magenta`, `Cyan`, `White`, `BrightBlack` through `BrightWhite`.
90
91Utilities: `Darken(c, 0.5)`, `Lighten(c, 0.35)`, `Complementary(c)`, `Alpha(c, 0.5)`, `Blend1D(steps, colors...)`, `Blend2D(w, h, angle, colors...)`.
92
93**Adaptive colors:**
94```go
95// Standalone
96hasDark := lipgloss.HasDarkBackground(os.Stdin, os.Stdout)
97ld := lipgloss.LightDark(hasDark)
98fg := ld(lipgloss.Color("#333"), lipgloss.Color("#EEE"))
99
100// Bubble Tea
101case tea.BackgroundColorMsg:
102 ld := lipgloss.LightDark(msg.IsDark())
103
104// Per-profile exact colors
105complete := lipgloss.Complete(colorprofile.Detect(os.Stdout, os.Environ()))
106c := complete(lipgloss.Color("1"), lipgloss.Color("124"), lipgloss.Color("#ff34ac"))
107```
108
109### Border
110
111```go
112// Built-in: NormalBorder, RoundedBorder, ThickBorder, DoubleBorder,
113// BlockBorder, OuterHalfBlockBorder, InnerHalfBlockBorder,
114// HiddenBorder, MarkdownBorder, ASCIIBorder
115
116s.Border(lipgloss.RoundedBorder()) // all sides
117s.Border(lipgloss.NormalBorder(), true, false) // top+bottom only
118s.BorderStyle(lipgloss.RoundedBorder()).BorderTop(true).BorderLeft(false)
119s.BorderForeground(lipgloss.Color("63")) // all sides
120s.BorderTopForeground(c).BorderBackground(c) // per-side
121
122// Gradient borders (2+ colors required)
123s.BorderForegroundBlend(c1, c2, c1) // wrap for seamless loop
124
125// Custom: lipgloss.Border{Top, Bottom, Left, Right, TopLeft, TopRight, ...}
126```
127
128If `BorderStyle()` is set without any side booleans, all 4 sides render. Setting any side explicitly means only those render.
129
130### Layout
131
132```go
133// Join blocks
134lipgloss.JoinHorizontal(lipgloss.Top, a, b, c) // vertical alignment
135lipgloss.JoinVertical(lipgloss.Center, a, b) // horizontal alignment
136
137// Place in whitespace
138lipgloss.Place(80, 30, lipgloss.Right, lipgloss.Bottom, content)
139lipgloss.PlaceHorizontal(80, lipgloss.Center, content)
140lipgloss.PlaceVertical(30, lipgloss.Bottom, content,
141 lipgloss.WithWhitespaceStyle(lipgloss.NewStyle().Background(c)),
142 lipgloss.WithWhitespaceChars("."),
143)
144
145// Measure
146w, h := lipgloss.Size(rendered) // also Width(), Height()
147
148// Compositor
149a := lipgloss.NewLayer(content).X(4).Y(2).Z(1)
150lipgloss.Compose(a, b).Render()
151
152// Wrap (preserves ANSI)
153lipgloss.Wrap(text, 40, " ")
154```
155
156### Table
157
158```go
159import "charm.land/lipgloss/v2/table"
160
161t := table.New().
162 Headers("NAME", "AGE").
163 Row("Alice", "30").
164 Rows([][]string{{"Bob", "25"}}...).
165 Border(lipgloss.RoundedBorder()).
166 BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99"))).
167 BorderHeader(true).BorderColumn(true).BorderRow(false).
168 Width(60).Height(20).Wrap(true).
169 StyleFunc(func(row, col int) lipgloss.Style {
170 if row == table.HeaderRow { // HeaderRow == -1
171 return lipgloss.NewStyle().Bold(true).Align(lipgloss.Center)
172 }
173 return lipgloss.NewStyle().Padding(0, 1)
174 })
175lipgloss.Println(t)
176
177// Custom data: implement table.Data{At(row,cell)string, Rows()int, Columns()int}
178// Filtering: table.NewFilter(data).Filter(func(row int) bool { ... })
179// Markdown: table.New().Border(lipgloss.MarkdownBorder()).BorderTop(false).BorderBottom(false)
180```
181
182### List
183
184```go
185import "charm.land/lipgloss/v2/list"
186
187l := list.New("A", "B", "C")
188l := list.New("Fruits", list.New("Apple", "Banana"), "Veggies", list.New("Carrot"))
189
190// Enumerators: Bullet (default), Arabic, Alphabet, Roman, Dash, Asterisk
191l.Enumerator(list.Arabic)
192l.EnumeratorStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99")).MarginRight(1))
193l.ItemStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("212")))
194l.ItemStyleFunc(func(items list.Items, i int) lipgloss.Style { ... })
195
196// Custom: func(items list.Items, i int) string
197l.Item("incremental").Offset(1, -1) // pagination
198```
199
200### Tree
201
202```go
203import "charm.land/lipgloss/v2/tree"
204
205t := tree.Root("Project").
206 Child("src", tree.Root("cmd").Child("main.go")).
207 Child("README.md")
208
209// Enumerators: DefaultEnumerator (square), RoundedEnumerator (rounded)
210t.Enumerator(tree.RoundedEnumerator)
211t.RootStyle(s).ItemStyle(s).EnumeratorStyle(s)
212t.ItemStyleFunc(func(children tree.Children, i int) lipgloss.Style { ... })
213t.Width(40).Hide(true)
214```
215
216## Common Patterns
217
218### 1. Styled card
219
220```go
221func Card(title, body string, w int) string {
222 head := lipgloss.NewStyle().Bold(true).
223 Foreground(lipgloss.Color("#FAFAFA")).Background(lipgloss.Color("#7D56F4")).
224 Padding(0, 1).Width(w)
225 frame := lipgloss.NewStyle().Padding(1, 2).Width(w).
226 Border(lipgloss.RoundedBorder()).BorderForeground(lipgloss.Color("#7D56F4"))
227 return lipgloss.JoinVertical(lipgloss.Left, head.Render(title), frame.Render(body))
228}
229```
230
231### 2. Two-column layout
232
233```go
234func Columns(left, right string, total int) string {
235 col := lipgloss.NewStyle().Width(total / 2).Padding(1, 2)
236 return lipgloss.JoinHorizontal(lipgloss.Top, col.Render(left), col.Render(right))
237}
238```
239
240### 3. Adaptive theme
241
242```go
243func NewTheme(hasDark bool) Theme {
244 ld := lipgloss.LightDark(hasDark)
245 return Theme{
246 Primary: ld(lipgloss.Color("#5A56E0"), lipgloss.Color("#7571F9")),
247 Subtle: ld(lipgloss.Color("#999"), lipgloss.Color("#666")),
248 }
249}
250```
251
252### 4. Alternating-row table
253
254```go
255t := table.New().Headers(headers...).Rows(rows...).
256 Border(lipgloss.RoundedBorder()).
257 BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99"))).
258 StyleFunc(func(row, col int) lipgloss.Style {
259 base := lipgloss.NewStyle().Padding(0, 1)
260 if row == table.HeaderRow { return base.Bold(true) }
261 if row%2 == 0 { return base.Foreground(lipgloss.Color("245")) }
262 return base.Foreground(lipgloss.Color("241"))
263 })
264```
265
266## Integration Patterns
267
268### Bubble Tea
269
270```go
271func (m model) Init() tea.Cmd { return tea.RequestBackgroundColor }
272func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
273 switch msg := msg.(type) {
274 case tea.BackgroundColorMsg:
275 m.styles = newStyles(msg.IsDark())
276 }
277 return m, nil
278}
279func (m model) View() string {
280 return m.styles.title.Render("My App")
281 // Bubble Tea handles downsampling - no lipgloss.Println needed
282}
283```
284
285### Glamour (Markdown)
286
287```go
288md, _ := glamour.Render(content, "dark")
289frame := lipgloss.NewStyle().Border(lipgloss.RoundedBorder()).Padding(1, 2).Width(80)
290lipgloss.Println(frame.Render(md))
291```
292
293## Common Mistakes
294
2951. **`fmt.Println` instead of `lipgloss.Println`** - no color downsampling. Always use lipgloss writers for standalone apps.
2962. **Width includes padding and borders** - `Width(40)` is 40 total cells, not content width.
2973. **`Color()` is a function in v2** - returns `color.Color`, not a type literal.
2984. **`Inherit()` skips margins/padding** - only text formatting and colors are inherited.
2995. **v1/v2 import mixing** - v2 is `charm.land/lipgloss/v2`. Sub-packages: `charm.land/lipgloss/v2/{table,list,tree}`.
3006. **`table.HeaderRow` is -1** - not 0. Data rows start at 0.
3017. **Border side defaults** - `BorderStyle()` alone renders all 4 sides. Setting any `BorderTop/Right/Bottom/Left` explicitly means only those render.
3028. **Renderer usage** - `*Renderer` does not exist in v2. Remove all renderer references.
303
304## Checklist
305
306- [ ] Import `charm.land/lipgloss/v2` (not `github.com/charmbracelet/lipgloss`)
307- [ ] Colors: `lipgloss.Color("...")` function call, returns `color.Color`
308- [ ] Output: `lipgloss.Println` for standalone apps
309- [ ] Width accounts for padding + border sizes
310- [ ] Table `StyleFunc` handles `table.HeaderRow` (-1)
311- [ ] Adaptive colors: `lipgloss.LightDark()`, not removed `lipgloss.AdaptiveColor`
312- [ ] No `*Renderer`, no `.Copy()` - both removed in v2
313- [ ] Sub-package imports: `charm.land/lipgloss/v2/{table,list,tree}`