Lip Gloss styles terminal cells without owning the event loop
Lip Gloss v2 gives Go programs a declarative style value that can set color, bold or underline text, width, height, padding, margins, alignment, and borders. Styles are values, so assigning one creates a copy and later changes do not mutate the original. This works well for a TUI with a small set of named styles shared across views.
The library goes beyond colored strings. It can join blocks horizontally or vertically, place text within a measured area, wrap ANSI content, and report rendered width and height. Its subpackages render tables, lists, and trees. A cell-based compositor adds positioned layers and can map mouse coordinates back to a layer. Those tools cover much of the drawing work around a Bubble Tea model while leaving input and state management elsewhere.
Color support spans 1-bit output, the 16 standard ANSI colors, the 256-color palette, and 24-bit true color. Lip Gloss can downsample to the detected profile when output goes through its print or sprint functions. Hyperlinks degrade when a terminal does not support them, and colors can disappear in plain output. That adaptation is helpful, but it means a screenshot from one terminal is not a universal rendering contract.
Version 2 moved color decisions to the output boundary
Version 2 uses the module path charm.land/lipgloss/v2 and removes the old Renderer type used throughout v1. Style.Render now emits full-fidelity ANSI, while lipgloss.Println, Fprintln, and Sprint perform profile-aware downsampling. Bubble Tea v2 handles the output layer for you. A standalone CLI that keeps using fmt.Println(style.Render(...)) can miss the new fallback behavior.
The color API also changed. Color is now a function returning Go's color.Color, and the old TerminalColor interface is gone. Adaptive and complete colors moved to a compatibility package or to explicit LightDark and Complete helpers. The upgrade guide gives direct replacements, but this is still a source migration. An established v1 application should budget time for imports, renderer fields, output calls, and color declarations.
The new split is sensible for libraries that render strings before deciding where they will go. A program may send one view to a true-color terminal and another to a log. Keeping styles as plain values avoids a renderer pointer hidden inside every style. The price is visible responsibility at the output edge, which is exactly where a rushed v1 migration can appear correct on a developer laptop and wrong in redirected output.
What happened when we ran it
Our sandbox installed commit 6a419c6 in 30 seconds and fetched 24 packages. The repository held 304 files, about 15,697 source lines, and occupied 0.7 MB before installation. It was a fresh unprivileged Debian container with 3 CPUs, 8 GB of RAM, no secrets, and the supplied golang:1.24-bookworm image. The install completed without an error.
The build succeeded in 24 seconds. Tests followed in 7 seconds, with go test reporting 8 passed and 0 failed. Six CI workflow files were present. Our scan found no Dockerfile and no tests directory, which is ordinary for a Go library whose test files live beside package code. These results cover repository mechanics; they do not compare terminal rendering speed or visual accuracy across emulators.
One version detail deserves attention: go.mod declares Go 1.26.7, while the named sandbox image was Go 1.24. All 3 measured steps still completed. The supplied run does not explain how that version difference was resolved, so we will not guess. For a locked-down build environment, inspect the Go toolchain behavior and pin the version you intend to allow before adding Lip Gloss to CI.
Unicode width and terminal queries remain platform work
Release v2.0.6 added proper Devanagari rendering and automatic use of terminal mode 2027 for grapheme-aware width when supported. It also stopped table columns from shrinking to zero. These fixes show why terminal styling is harder than emitting an ANSI color code: visual width depends on grapheme clusters, wide characters, terminal capabilities, borders, and the state carried across lines.
The open reports are similarly concrete. Issue 740 shows an ANSI span crossing a newline and coloring padding or borders until the reset arrives. Issue 731 reports that style flags stored above bit 31 are dropped on 32-bit targets, affecting left borders and inline mode. Pull requests exist around both areas, but an open patch is not a released fix. Test multiline styled content and every CPU architecture you ship.
Windows background detection has a sharper consequence. Issue 745 reports that HasDarkBackground can wait indefinitely when standard input is redirected but a console exists, including in programs importing the compatibility package. The report covers v2.0.5 and v2.0.6, and pull request 746 proposes a fix. Until a release contains that fix, a Windows CLI used by editors, agents, or CI should avoid that query path or carry its own mitigation.
September activity shows maintenance and a large queue
The last repository push was September 13, 2026, and v2.0.6 shipped on August 11. GitHub showed 11,883 stars plus 148 open issues and pull requests combined. A separate search split that total into 67 issues and 81 pull requests. The queue is large, yet work remained current: Windows background-query and color-lightness pull requests were updated or opened in late September.
Lip Gloss is the right layer when a Go application already owns its update loop and needs reliable terminal composition. Its 30-second install, 24-second build, and green 8-test run remove most setup doubt. The harder questions live at the edges: v1 migration, Unicode width, color fallback, redirected streams, and uncommon architectures. If you need styled cells and layout control, accept those tests. If you need ready-made interactive widgets, choose a fuller TUI framework.

