Lip Gloss

TUIStylingTerminalCSS-likeGo

GitHub Overview

charmbracelet/lipgloss

Style definitions for nice terminal layouts 👄

Stars9,305
Watchers35
Forks259
Created:March 1, 2021
Language:Go
License:MIT License

Topics

cligogolanghacktoberfestlayoutstyletui

Star History

charmbracelet/lipgloss Star History
Data as of: 7/25/2025, 11:09 AM

Lip Gloss

Lip Gloss is a styling library for terminal applications developed by Charmbracelet. With an intuitive CSS-like API, it allows you to apply beautiful layouts and styles to terminals. As part of the Bubble Tea and Charm ecosystem, it's used in many projects.

Features

CSS-like Styling

  • Properties: Colors, padding, margins, borders
  • Layout: Flexbox-like alignment, positioning
  • Text Decoration: Bold, italic, underline, strikethrough
  • Animation: Blinking, fading

Advanced Features

  • Adaptive Colors: Color adjustment based on terminal capabilities
  • Gradients: Gradient backgrounds
  • Responsive: Adjustments based on terminal size
  • Style Inheritance: CSS-like style inheritance

Utilities

  • Table Rendering: Beautiful table creation
  • Join Functions: Element combination
  • Wrapping and Truncation: Text processing
  • Custom Renderers: Extensible rendering system

Performance

  • Zero Allocation: Style reuse
  • Efficient Rendering: Minimal ANSI codes
  • Caching: Style calculation caching
  • Lightweight: Minimal dependencies

Basic Usage

Installation

go get github.com/charmbracelet/lipgloss

Hello World

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // Basic style
    style := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("#FAFAFA")).
        Background(lipgloss.Color("#7D56F4")).
        PaddingTop(2).
        PaddingLeft(4).
        Width(22)
    
    fmt.Println(style.Render("Hello, Lip Gloss!"))
}

Combining Styles

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // Base style
    var baseStyle = lipgloss.NewStyle().
        PaddingLeft(1).
        PaddingRight(1)
    
    // Title style
    titleStyle := baseStyle.Copy().
        Bold(true).
        Foreground(lipgloss.Color("#FF00FF")).
        MarginTop(1).
        MarginBottom(1)
    
    // Content style
    contentStyle := baseStyle.Copy().
        Foreground(lipgloss.Color("#CCCCCC")).
        Padding(1, 2)
    
    // Border style
    borderStyle := lipgloss.NewStyle().
        Border(lipgloss.RoundedBorder()).
        BorderForeground(lipgloss.Color("62")).
        Padding(1, 2)
    
    // Rendering
    title := titleStyle.Render("Welcome")
    content := contentStyle.Render("This is content styled\nwith Lip Gloss.")
    
    // Combining
    output := lipgloss.JoinVertical(lipgloss.Left, title, content)
    
    fmt.Println(borderStyle.Render(output))
}

Layout and Positioning

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // Get terminal size
    width := 80
    height := 24
    
    // Header
    headerStyle := lipgloss.NewStyle().
        Background(lipgloss.Color("62")).
        Foreground(lipgloss.Color("230")).
        Bold(true).
        Align(lipgloss.Center).
        Width(width).
        Padding(0, 1)
    
    header := headerStyle.Render("🌈 My Application")
    
    // Sidebar
    sidebarStyle := lipgloss.NewStyle().
        Border(lipgloss.NormalBorder(), false, true, false, false).
        BorderForeground(lipgloss.Color("240")).
        Width(20).
        Height(height - 4).
        Padding(1)
    
    sidebar := sidebarStyle.Render("Menu\n\n• Home\n• About\n• Contact")
    
    // Main content
    mainStyle := lipgloss.NewStyle().
        Width(width - 22).
        Height(height - 4).
        Padding(2).
        Align(lipgloss.Center, lipgloss.Center)
    
    main := mainStyle.Render("Main Content Area")
    
    // Footer
    footerStyle := lipgloss.NewStyle().
        Background(lipgloss.Color("235")).
        Foreground(lipgloss.Color("241")).
        Align(lipgloss.Center).
        Width(width)
    
    footer := footerStyle.Render("Press q to quit")
    
    // Assemble layout
    body := lipgloss.JoinHorizontal(lipgloss.Top, sidebar, main)
    doc := lipgloss.JoinVertical(lipgloss.Left, header, body, footer)
    
    fmt.Println(doc)
}

Creating Tables

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
    "github.com/charmbracelet/lipgloss/table"
)

func main() {
    // Table data
    rows := [][]string{
        {"ID", "Name", "Age", "City"},
        {"1", "Alice", "30", "New York"},
        {"2", "Bob", "25", "Los Angeles"},
        {"3", "Charlie", "35", "Chicago"},
    }
    
    // Create table
    t := table.New().
        Border(lipgloss.NormalBorder()).
        BorderStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("99")))
    
    // Header style
    headerStyle := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("230")).
        Background(lipgloss.Color("63")).
        Align(lipgloss.Center)
    
    // Even row style
    evenRowStyle := lipgloss.NewStyle().
        Foreground(lipgloss.Color("245"))
    
    // Odd row style
    oddRowStyle := lipgloss.NewStyle().
        Foreground(lipgloss.Color("250"))
    
    // Apply styles to table
    t.Headers(rows[0]...).
        StyleFunc(func(row, col int) lipgloss.Style {
            if row == 0 {
                return headerStyle
            }
            if row%2 == 0 {
                return evenRowStyle
            }
            return oddRowStyle
        })
    
    // Add data
    for _, row := range rows[1:] {
        t.Row(row...)
    }
    
    fmt.Println(t)
}

Gradients and Animation

package main

import (
    "fmt"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    // Gradient style
    gradientStyle := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("#FF00FF")).
        Background(lipgloss.Color("#FFD700")).
        Width(40).
        Align(lipgloss.Center).
        Margin(1)
    
    // Blinking style
    blinkStyle := lipgloss.NewStyle().
        Blink(true).
        Foreground(lipgloss.Color("#FF0000")).
        Bold(true)
    
    // Underline style
    underlineStyle := lipgloss.NewStyle().
        Underline(true).
        UnderlineSpaces(true).
        Foreground(lipgloss.Color("#00FF00"))
    
    // Reverse style
    reverseStyle := lipgloss.NewStyle().
        Reverse(true).
        Padding(0, 2)
    
    fmt.Println(gradientStyle.Render("Gradient Background"))
    fmt.Println(blinkStyle.Render("Blinking Text"))
    fmt.Println(underlineStyle.Render("Underlined Text"))
    fmt.Println(reverseStyle.Render("Reversed Text"))
}

Advanced Features

Adaptive Colors

// Color selection based on terminal capabilities
adaptiveColor := lipgloss.AdaptiveColor{
    Light: "#000000",
    Dark:  "#FFFFFF",
}

style := lipgloss.NewStyle().
    Foreground(adaptiveColor)

Custom Borders

// Define custom border
customBorder := lipgloss.Border{
    Top:         "━",
    Bottom:      "━",
    Left:        "┃",
    Right:       "┃",
    TopLeft:     "┏",
    TopRight:    "┓",
    BottomLeft:  "┗",
    BottomRight: "┛",
}

style := lipgloss.NewStyle().
    Border(customBorder).
    BorderForeground(lipgloss.Color("63"))

Responsive Design

func responsiveLayout(width int) string {
    var style lipgloss.Style
    
    if width < 40 {
        // Mobile layout
        style = lipgloss.NewStyle().
            Width(width).
            Padding(1)
    } else if width < 80 {
        // Tablet layout
        style = lipgloss.NewStyle().
            Width(width).
            Padding(2).
            Margin(1)
    } else {
        // Desktop layout
        style = lipgloss.NewStyle().
            Width(width / 2).
            Padding(3).
            Margin(2).
            Border(lipgloss.NormalBorder())
    }
    
    return style.Render("Content")
}

Componentization

// Button component
func Button(label string, primary bool) string {
    style := lipgloss.NewStyle().
        Padding(0, 3).
        Bold(true).
        Border(lipgloss.RoundedBorder())
    
    if primary {
        style = style.
            Foreground(lipgloss.Color("#FFFFFF")).
            Background(lipgloss.Color("#7D56F4")).
            BorderForeground(lipgloss.Color("#7D56F4"))
    } else {
        style = style.
            Foreground(lipgloss.Color("#7D56F4")).
            BorderForeground(lipgloss.Color("#7D56F4"))
    }
    
    return style.Render(label)
}

// Card component
func Card(title, content string) string {
    titleStyle := lipgloss.NewStyle().
        Bold(true).
        Foreground(lipgloss.Color("#FF00FF")).
        MarginBottom(1)
    
    contentStyle := lipgloss.NewStyle().
        Foreground(lipgloss.Color("#CCCCCC"))
    
    cardStyle := lipgloss.NewStyle().
        Border(lipgloss.RoundedBorder()).
        BorderForeground(lipgloss.Color("#666666")).
        Padding(1, 2).
        Width(40)
    
    card := lipgloss.JoinVertical(
        lipgloss.Left,
        titleStyle.Render(title),
        contentStyle.Render(content),
    )
    
    return cardStyle.Render(card)
}

Ecosystem

Charmbracelet Tools

  • Bubble Tea: TUI framework
  • Bubbles: TUI component collection
  • Glamour: Markdown renderer
  • Glow: Markdown viewer

Adoption Examples

  • gh: GitHub CLI
  • lazygit: Git TUI
  • soft-serve: Git server
  • mods: AI chat CLI

Advantages

  • Intuitive: CSS-like API
  • Beautiful: Professional appearance
  • Flexible: Easy componentization
  • Efficient: Performance focused
  • Active: Continuous development by Charmbracelet

Limitations

  • Styling Only: No interactive features
  • Framework Dependent: Cannot create TUI apps alone
  • Layout Limitations: Complex layouts require manual calculation

Comparison with Other Libraries

FeatureLip Glosstviewtermui
PurposeStylingFull TUIDashboard
APICSS-likeWidgetWidget
Learning CostLowLowMedium
FlexibilityVery HighMediumLow
EcosystemCharmbraceletIndependentIndependent

Summary

Lip Gloss is an excellent library for applying beautiful styles to terminal applications. With its intuitive CSS-like API, developers can easily create professional-looking terminal UIs. While it cannot build complete TUI applications alone, when combined with Bubble Tea, it enables the creation of the most modern and beautiful TUI applications.