Skip to content

Repository files navigation

Box CLI Maker

logo

Go Reference Go GitHub release Mentioned in Awesome Go

Box CLI Maker is a Go library for rendering highly customizable boxes in the terminal.

Used by kubernetes logo kubernetes/minikube · Featured in Golang Weekly (×3) and GitHub's Release Radar

a weather card rendered with Box CLI Maker

Features

  • 9 built‑in styles (Single, Double, Round, Bold, SingleDouble, DoubleSingle, Classic, Hidden, Block)
  • Custom glyphs for all corners and edges
  • Title positions: Inside, Top, Bottom
  • Title and Content alignment: Left, Center, Right
  • Inner padding and outer margin
  • Optional content wrapping with WrapContent and WrapLimit
  • Color support with:
    • First 16 ANSI color names
    • #RGB, #RRGGBB, rgb:RRRR/GGGG/BBBB, rgba:RRRR/GGGG/BBBB/AAAA
    • Automatic conversion to the terminal's color capability; suppressed for NO_COLOR and piped output
  • Unicode and emoji support with proper width handling
  • Derived styles with Copy() for building box families from a shared base
  • Explicit errors from Render, plus MustRender for panic‑on‑error

Installation

go get github.com/box-cli-maker/box-cli-maker/v3

Quick Start

package main

import (
    "fmt"

    box "github.com/box-cli-maker/box-cli-maker/v3"
)

func main() {
    b := box.NewBox().
        Style(box.Single).  // single-line border
        Padding(2, 1).      // inner padding: x (horizontal), y (vertical)
        Margin(3, 1).       // outer margin: x (horizontal), y (vertical)
        TitlePosition(box.Top).
        ContentAlign(box.Center).
        Color(box.Cyan).
        TitleColor(box.BrightYellow)

    out, err := b.Render("Box CLI Maker", "Render highly customizable boxes\nin the terminal")
    if err != nil {
        panic(err)
    }
    fmt.Println(out)
}

NewBox constructs a box with the default Single style.
Configure it via fluent methods, then call Render (or MustRender) to get the box as a string.

API Overview

Construction

b := box.NewBox()

You can clone a configured box and tweak it:

base := box.NewBox().
        Style(box.Single).
        Padding(2, 1).
        ContentAlign(box.Left)

info := base.Copy().Color(box.Green)
warn := base.Copy().Color(box.Yellow)

Styles

Select a built‑in style:

b.Style(box.Double)

Styles showcase

box.Single

single

box.SingleDouble

single double

box.Double

double

box.DoubleSingle

double single

box.Bold

bold

box.Round

round

box.Hidden

hidden

box.Classic

classic

box.Block

block

You can override any glyph after choosing a style:

b.Style(box.Single).
  TopLeft("+").
  TopRight("+").
  BottomLeft("+").
  BottomRight("+").
  Horizontal("-").
  Vertical("|")

Titles and Alignment

Title position:

TitlePosition decides where the title goes: inside the box, on the top border, or on the bottom border. The default is box.Inside.

b.TitlePosition(box.Inside)
b.TitlePosition(box.Top)
b.TitlePosition(box.Bottom)

Title Position showcase

box.Inside

single

box.Top

top

box.Bottom

bottom

Title alignment:

TitleAlign decides where the title sits: across the box for Inside titles, or along the border for Top and Bottom titles. It works together with TitlePosition, and the two can be called in any order:

b.TitlePosition(box.Top).TitleAlign(box.Center) // title centered on the top border

The values are box.Left, box.Center, and box.Right. If you don't set it, Inside titles are centered and Top/Bottom titles are left‑aligned.

Title Alignment showcase

box.Left

box.Inside
inside left

box.Top
top left

box.Bottom
bottom left

box.Center

box.Inside
inside center

box.Top
top center

box.Bottom
bottom center

box.Right

box.Inside
inside right

box.Top
top right

box.Bottom
bottom right

Content alignment:

ContentAlign decides whether content lines sit on the left, in the center, or on the right of the box. The box is as wide as its longest line, so it's the shorter lines that move. The default is box.Left.

b.ContentAlign(box.Left)
b.ContentAlign(box.Center)
b.ContentAlign(box.Right)

Content Alignment showcase

box.Left

left

box.Center

center

box.Right

right

Padding

Padding adds space inside the box borders, between the border and the content: px columns of spaces on both the left and right of every line, and py blank rows above and below the content.

b.Padding(px, py) // set both: horizontal (px), then vertical (py)
b.HPadding(px)    // horizontal only
b.VPadding(py)    // vertical only

Horizontal comes first — the reverse of CSS's padding: vertical horizontal shorthand.

Padding defaults to 0. Setting negative padding causes Render to return an error.

padding comparison

Margin

Margin adds space outside the box borders — horizontal margin prepends spaces to every line, vertical margin adds blank lines above and below.

b.Margin(mx, my) // horizontal (mx) and vertical (my) margin
b.HMargin(mx)    // horizontal only
b.VMargin(my)    // vertical only

The argument order matches Padding: horizontal first.

Margin defaults to 0. Setting negative margin causes Render to return an error.

margin comparison

Wrapping

Long content can wrap automatically to fit the terminal, or at an exact width with WrapLimit. Wrapping is off by default.

b.WrapContent(true)       // enable wrapping (default: 2/3 of terminal width, minus any HMargin)
b.WrapLimit(40)           // set explicit wrap width (enables wrapping)
b.WrapContent(false)      // disable wrapping

wrapping comparison

Tabs are expanded (at 8‑column stops) before wrapping, so the configured limit is honored even for tab‑heavy content.

Render returns an error if the wrap limit is not positive or the terminal width cannot be determined when wrapping is enabled without a limit.

Colors

Colors can be applied to:

  • Title: TitleColor
  • Content: ContentColor
  • Border: Color

Accepted formats:

  • The 16 ANSI color names: box.Black, box.Red, box.Green, box.Yellow, box.Blue, box.Magenta, box.Cyan, box.White — each also available with a Bright prefix (e.g. box.BrightYellow) or its Hi alias (e.g. box.HiRed).
  • Hex and XParseColor formats (TrueColor and 8-bit): #RGB, #RRGGBB, rgb:RRRR/GGGG/BBBB, rgba:RRRR/GGGG/BBBB/AAAA

Example:

b.TitleColor(box.BrightYellow)
b.ContentColor("#00FF00")
b.Color("rgb:0000/ffff/0000")

Invalid colors cause Render to return an error.

Colors automatically adapt to what the terminal supports (TrueColor, 256‑color, or 16‑color). When the output can't show color at all — NO_COLOR set, TERM=dumb, or output piped to a file — colors are dropped entirely, so logs stay free of escape codes.

Styled Content and ANSI Safety

Your text may already be styled before it reaches the box — by your logger, a color library, or your own escape codes. That's fine: pass it in as-is, and the box renders correctly around it.

styled := "\x1b[31mthis red part is long enough to wrap\x1b[0m and this part is plain"
out, _ := box.NewBox().WrapLimit(24).Render("", styled)

unclosed styling bleeding into the border, versus staying on the text

What you can rely on:

  • Colors and styles in your text never leak into the borders or padding.
  • Styling survives wrapping: when a colored sentence breaks across lines, every line keeps its color.
  • Clickable hyperlinks (OSC 8) stay clickable — and the borders never become part of the link.
  • This works together with Color / ContentColor: your styling and the box's styling don't fight.

There is nothing to enable — this is how Render always behaves. (For the curious: every rendered line is made self‑contained by closing any open styling at the line's end and re‑opening it on the next line.)

Rendering

out, err := b.Render("Title", "Content")
if err != nil {
    // handle invalid style, colors, padding, wrapping, etc.
}

fmt.Println(out)

Render returns an error if:

  • The BoxStyle is invalid
  • The TitlePosition is invalid
  • The TitleAlign or ContentAlign is invalid
  • The wrap limit is not positive
  • Padding or margin is negative
  • A multiline title is used with a non‑Inside title position
  • Any configured colors are invalid
  • Terminal width detection fails when needed for wrapping

For convenience:

out := b.MustRender("Title", "Content") // panics on error

Examples

The examples directory contains small, focused programs that showcase different features:

  • simple_box – minimal single box with title and content.
  • content_align – compare Left, Center, and Right content alignment.
  • content_wrap – demonstrate WrapContent / WrapLimit with long text.
  • titles – every title position (Inside, Top, Bottom) with every alignment (Left, Center, Right).
  • spacing – inner padding vs outer margin, separately and combined.
  • box_styles – render all built‑in border styles and colors.
  • custom_box – build boxes using fully custom corner/edge glyphs.
  • ansi_styles_and_links – use bold/underline/blink/strikethrough and OSC 8 hyperlinks.
  • colors_and_unicode – mix hex/ANSI colors with CJK, emoji, and wrapping.
  • ansi_art – render more decorative/"artistic" boxes.
  • shared_styles – derive multiple boxes from a shared base style with Copy.
  • ksctl – real‑world example from ksctl showing wide titles vs narrow content.
  • lolcat – rainbow color demo using custom ANSI styling helpers.
  • readme – code used to generate the screenshot at the top of this README.

Unicode, Emoji, and Width Handling

This library uses mattn/go-runewidth and github.com/charmbracelet/x/ansi to handle:

  • Wide characters (e.g., CJK)
  • Emojis and other multi‑cell glyphs
  • Stripping ANSI sequences when measuring widths

Note:

  1. Rendering quality depends on the terminal emulator and font. Some combinations may misalign visually.
  2. Indic scripts and complex text may not display correctly in most terminals.
  3. Online playgrounds and many CI environments often use basic fonts and may not render Unicode/emoji correctly, so boxes may look misaligned there.

Migration from v2

v3 is a new major version with a redesigned API.

Key changes:

  • Config struct and New(Config) have been replaced with:

    b := box.NewBox().
        Style(box.Single).
        Padding(2, 1).
        TitlePosition(box.Top).
        ContentAlign(box.Left)
  • String‑based fields (Type, ContentAlign, TitlePos) are now strongly typed:

    • "Single"box.Single
    • "Top"box.Top
    • "Center"box.Center
  • Colors:

    • No more interface{} colors (uint, [3]uint, etc.).
    • Use ANSI names or the documented hex/rgb formats instead.
    • Invalid colors now error at Render time.
  • Print / Println behavior can be replicated by fmt.Println(b.MustRender(...)) or your own helper.

Read more at Migration guide.

The old v2 API remains available at:

go get github.com/Delta456/box-cli-maker/v2

but is no longer actively developed.

Using Box CLI Maker in your project? Add it to the adopters list — we'd love to feature it.

Sponsors

Thanks to CodeRabbit for sponsoring my open source work.

Acknowledgements

Thanks to:

for inspiration, and to all contributors who have improved this library over time.

License

Licensed under MIT.

About

Render highly customizable boxes in the terminal

Topics

Resources

Stars

650 stars

Watchers

5 watching

Forks

Releases

Packages

Used by

Contributors

Languages