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.SetFooters("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 │
├────┼─────────────┼────────┤
│ ID │ Fruit │ Stock │
└────┴─────────────┴────────┘
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 13 17:34:32 │
├───────────────────┤ ├─────────────────┤
│ Nuclear Generator │ │ May 13 17:33:32 │
├───────────────────┼────────┼─────────────────┤
│ Weapons Systems │ FAIL │ May 13 17:34:32 │
├───────────────────┼────────┤ │
│ 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("A", "B", "C")
t.AddRow("🔥 unicode 🔥 characters 🔥", "2", "3")
t.AddRow("4", "5", "6")
t.Render()
}
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()
}