Render highly customizable boxes in the terminal
- star 数
- 668
- watcher 数
- 5
- fork 数
- 25
- issue 数
- 7
- 最終更新
- 2026/09/18
Render highly customizable boxes in the terminal
Box CLI Maker is a Go library for rendering highly customizable boxes in the terminal.
Used by
kubernetes/minikube · Featured in Golang Weekly (×3) and GitHub's Release Radar
WrapContent and WrapLimit#RGB, #RRGGBB, rgb:RRRR/GGGG/BBBB, rgba:RRRR/GGGG/BBBB/AAAANO_COLOR and piped outputCopy() for building box families from a shared baseRender, plus MustRender for panic‑on‑errorgo get github.com/box-cli-maker/box-cli-maker/v3
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.
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)
Select a built‑in style:
b.Style(box.Double)
box.Single
box.SingleDouble
box.Double
box.DoubleSingle
box.Bold
box.Round
box.Hidden
box.Classic
box.Block
You can override any glyph after choosing a style:
b.Style(box.Single). TopLeft("+"). TopRight("+"). BottomLeft("+"). BottomRight("+"). Horizontal("-"). Vertical("|")
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)
box.Inside
box.Top
box.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.
box.Left
box.Center
box.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)
box.Left
box.Center
box.Right
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.
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.
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
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 can be applied to:
TitleColorContentColorColorAccepted formats:
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).#RGB, #RRGGBB, rgb:RRRR/GGGG/BBBB, rgba:RRRR/GGGG/BBBB/AAAAExample:
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.
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)
What you can rely on:
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.)
out, err := b.Render("Title", "Content") if err != nil { // handle invalid style, colors, padding, wrapping, etc. } fmt.Println(out)
Render returns an error if:
BoxStyle is invalidTitlePosition is invalidTitleAlign or ContentAlign is invalidInside title positionFor convenience:
out := b.MustRender("Title", "Content") // panics on error
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.This library uses mattn/go-runewidth and github.com/charmbracelet/x/ansi to handle:
Note:
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.CenterColors:
interface{} colors (uint, [3]uint, etc.).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.
Thanks to CodeRabbit for sponsoring my open source work.
Thanks to:
for inspiration, and to all contributors who have improved this library over time.
Licensed under MIT.