This is a Go module for rendering tables in the terminal.
↕️ Headers/footers- ↩️ Text wrapping
- 🔀 Auto-merging of cells
!?️ Customisable line/border characters- 🌈 Customisable line/border colours
- ⏯️ Individually enable/disable borders, row lines
↔️ Set alignments on a per-column basis, with separate settings for headers/footers- 📐 Intelligently wrap/pad/measure ANSI coloured input
- 👯 Support for double-width unicode characters
- 📊 Load data from CSV files
Check out the documentation for full features/usage.
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
├────┼─────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼─────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼─────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
└────┴─────────────┴────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetRowLines(false) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
│ 2 │ Banana │ 88,041 │
│ 3 │ Cherry │ 342 │
│ 4 │ Dragonfruit │ 1 │
└────┴─────────────┴────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetBorders(false) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
ID │ Fruit │ Stock
────┼─────────────┼────────
1 │ Apple │ 14
────┼─────────────┼────────
2 │ Banana │ 88,041
────┼─────────────┼────────
3 │ Cherry │ 342
────┼─────────────┼────────
4 │ Dragonfruit │ 1
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetRowLines(false) t.SetBorders(false) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
ID │ Fruit │ Stock
────┼─────────────┼────────
1 │ Apple │ 14
2 │ Banana │ 88,041
3 │ Cherry │ 342
4 │ Dragonfruit │ 1
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetRowLines(false) t.SetBorderLeft(true) t.SetBorderRight(false) t.SetBorderTop(true) t.SetBorderBottom(false) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
┌────┬─────────────┬────────
│ ID │ Fruit │ Stock
├────┼─────────────┼────────
│ 1 │ Apple │ 14
│ 2 │ Banana │ 88,041
│ 3 │ Cherry │ 342
│ 4 │ Dragonfruit │ 1
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetHeaders("ID", "Fruit", "Stock") t.SetRowLines(false) t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.SetFooters("", "Count", "4") t.Render() }
┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
│ 2 │ Banana │ 88,041 │
│ 3 │ Cherry │ 342 │
│ 4 │ Dragonfruit │ 1 │
├────┼─────────────┼────────┤
│ │ Count │ 4 │
└────┴─────────────┴────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetPadding(5) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
┌────────────┬─────────────────────┬────────────────┐
│ ID │ Fruit │ Stock │
├────────────┼─────────────────────┼────────────────┤
│ 1 │ Apple │ 14 │
├────────────┼─────────────────────┼────────────────┤
│ 2 │ Banana │ 88,041 │
├────────────┼─────────────────────┼────────────────┤
│ 3 │ Cherry │ 342 │
├────────────┼─────────────────────┼────────────────┤
│ 4 │ Dragonfruit │ 1 │
└────────────┴─────────────────────┴────────────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetAlignment(table.AlignLeft, table.AlignCenter, table.AlignRight) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
┌────┬─────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
├────┼─────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼─────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼─────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
└────┴─────────────┴────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetDividers(table.UnicodeRoundedDividers) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
╭────┬─────────────┬────────╮
│ ID │ Fruit │ Stock │
├────┼─────────────┼────────┤
│ 1 │ Apple │ 14 │
├────┼─────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼─────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼─────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
╰────┴─────────────┴────────╯
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetDividers(table.Dividers{ ALL: "@", NES: "@", NSW: "@", NEW: "@", ESW: "@", NE: "@", NW: "@", SW: "@", ES: "@", EW: "~", NS: "!", }) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! ID ! Fruit ! Stock !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 1 ! Apple ! 14 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 2 ! Banana ! 88,041 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 3 ! Cherry ! 342 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
! 4 ! Dragonfruit ! 1 !
@~~~~@~~~~~~~~~~~~~@~~~~~~~~@
package main import ( "os" "time" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetAutoMerge(true) t.SetHeaders("System", "Status", "Last Check") t.AddRow("Life Support", "OK", time.Now().Format(time.Stamp)) t.AddRow("Nuclear Generator", "OK", time.Now().Add(-time.Minute).Format(time.Stamp)) t.AddRow("Weapons Systems", "FAIL", time.Now().Format(time.Stamp)) t.AddRow("Shields", "OK", time.Now().Format(time.Stamp)) t.Render() }
┌───────────────────┬────────┬────────────────┐
│ System │ Status │ Last Check │
├───────────────────┼────────┼────────────────┤
│ Life Support │ OK │ May 2 09:28:05 │
├───────────────────┤ ├────────────────┤
│ Nuclear Generator │ │ May 2 09:27:05 │
├───────────────────┼────────┼────────────────┤
│ Weapons Systems │ FAIL │ May 2 09:28:05 │
├───────────────────┼────────┤ │
│ Shields │ OK │ │
└───────────────────┴────────┴────────────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { f, err := os.Open("./_examples/12-load-data-from-csv/data.csv") if err != nil { panic(err) } t := table.New(os.Stdout) if err := t.LoadCSV(f, true); err != nil { panic(err) } t.Render() }
┌────┬────────────┬────────────────────────────────────────────┐
│ Id │ Date │ Message │
├────┼────────────┼────────────────────────────────────────────┤
│ 1 │ 2022年05月12日 │ Hello world! │
├────┼────────────┼────────────────────────────────────────────┤
│ 2 │ 2022年05月12日 │ These messages are loaded from a CSV file. │
├────┼────────────┼────────────────────────────────────────────┤
│ 3 │ 2022年05月13日 │ Incredible! │
└────┴────────────┴────────────────────────────────────────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetDividers(table.MarkdownDividers) t.SetBorderTop(false) t.SetBorderBottom(false) t.SetRowLines(false) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "Apple", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
| ID | Fruit | Stock |
|----|-------------|--------|
| 1 | Apple | 14 |
| 2 | Banana | 88,041 |
| 3 | Cherry | 342 |
| 4 | Dragonfruit | 1 |
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetHeaders("Namespace", "Resource", "Vulnerabilities", "Misconfigurations") t.AddHeaders("Namespace", "Resource", "Critical", "High", "Medium", "Low", "Unknown", "Critical", "High", "Medium", "Low", "Unknown") t.SetHeaderColSpans(0, 1, 1, 5, 5) t.SetAutoMergeHeaders(true) t.AddRow("default", "Deployment/app", "2", "5", "7", "8", "0", "0", "3", "5", "19", "0") t.AddRow("default", "Ingress/test", "-", "-", "-", "-", "-", "1", "0", "2", "17", "0") t.AddRow("default", "Service/test", "0", "0", "0", "1", "0", "3", "0", "4", "9", "0") t.Render() }
┌───────────┬────────────────┬──────────────────────────────────────────┬──────────────────────────────────────────┐
│ Namespace │ Resource │ Vulnerabilities │ Misconfigurations │
│ │ ├──────────┬──────┬────────┬─────┬─────────┼──────────┬──────┬────────┬─────┬─────────┤
│ │ │ Critical │ High │ Medium │ Low │ Unknown │ Critical │ High │ Medium │ Low │ Unknown │
├───────────┼────────────────┼──────────┼──────┼────────┼─────┼─────────┼──────────┼──────┼────────┼─────┼─────────┤
│ default │ Deployment/app │ 2 │ 5 │ 7 │ 8 │ 0 │ 0 │ 3 │ 5 │ 19 │ 0 │
├───────────┼────────────────┼──────────┼──────┼────────┼─────┼─────────┼──────────┼──────┼────────┼─────┼─────────┤
│ default │ Ingress/test │ - │ - │ - │ - │ - │ 1 │ 0 │ 2 │ 17 │ 0 │
├───────────┼────────────────┼──────────┼──────┼────────┼─────┼─────────┼──────────┼──────┼────────┼─────┼─────────┤
│ default │ Service/test │ 0 │ 0 │ 0 │ 1 │ 0 │ 3 │ 0 │ 4 │ 9 │ 0 │
└───────────┴────────────────┴──────────┴──────┴────────┴─────┴─────────┴──────────┴──────┴────────┴─────┴─────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetHeaders("ID", "Fruit", "Stock") t.AddRow("1", "01234567890123456789012345678901234567890123456789012345678901234567890123456789", "14") t.AddRow("2", "Banana", "88,041") t.AddRow("3", "Cherry", "342") t.AddRow("4", "Dragonfruit", "1") t.Render() }
┌────┬──────────────────────────────────────────────────────────────┬────────┐
│ ID │ Fruit │ Stock │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 1 │ 01234567890123456789012345678901234567890123456789012345678- │ 14 │
│ │ 901234567890123456789 │ │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 2 │ Banana │ 88,041 │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 3 │ Cherry │ 342 │
├────┼──────────────────────────────────────────────────────────────┼────────┤
│ 4 │ Dragonfruit │ 1 │
└────┴──────────────────────────────────────────────────────────────┴────────┘
package main import ( "os" "github.com/aquasecurity/table" ) func main() { t := table.New(os.Stdout) t.SetHeaders("A", "B", "C") t.AddRow("🔥 unicode 🔥 characters 🔥", "2", "3") t.AddRow("4", "5", "6") t.Render() }
a table with double-width runes
package main import ( "os" "github.com/aquasecurity/table" "github.com/liamg/tml" ) func main() { t := table.New(os.Stdout) t.SetHeaders("ID", "Fruit", "Stock", "Description") t.SetHeaderStyle(table.StyleBold) t.SetLineStyle(table.StyleBlue) t.SetDividers(table.UnicodeRoundedDividers) t.AddRow("1", tml.Sprintf("<green>Apple</green>"), "14", tml.Sprintf("An apple is an edible fruit produced by an apple tree (<italic>Malus domestica</italic>). ")) t.AddRow("2", tml.Sprintf("<yellow>Banana</yellow>"), "88,041", "A banana is an elongated, edible fruit - botanically a berry.") t.AddRow("3", tml.Sprintf("<red>Cherry</red>"), "342", "A cherry is the fruit of many plants of the genus Prunus, and is a fleshy drupe (stone fruit). ") t.AddRow("4", tml.Sprintf("<magenta>Dragonfruit</magenta>"), "1", "A dragonfruit is the fruit of several different cactus species indigenous to the Americas.") t.Render() }