Skip to content

Render a table

Renderer.Table renders a slice of structs or maps as an aligned text table — or, when the renderer's format is csv/tsv/markdown/json/yaml, in that machine-readable form instead. One call, every format.

From struct tags

Tag the fields you want as columns with table:"Header[,sortable]":

type Release struct {
    Tag     string `table:"Tag,sortable"`
    Date    string `table:"Date,sortable"`
    Assets  int    `table:"Assets,sortable"`
    Notes   string `table:"-"` // excluded
}

r := output.New(output.WithWriter(os.Stdout), output.WithFormat(output.FormatText))
_ = r.Table(releases, output.WithSortBy("Date"), output.WithSortDescending())
Tag     Date        Assets
v1.4.0  2026-07-20  6
v1.3.0  2026-06-11  6

Explicit columns (and maps)

[]map[string]any has no tags, so pass columns explicitly. WithColumns also lets you set widths and per-cell formatters:

_ = r.Table(rows, output.WithColumns(
    output.Column{Header: "Name", Field: "name", Sortable: true},
    output.Column{Header: "Size", Field: "bytes", Formatter: humanize},
))

Options

Option Effect
WithColumns(cols...) define columns explicitly (required for maps)
WithSortBy(header) sort by a Sortable column (numeric-aware)
WithSortDescending() reverse the sort
WithNoHeader() omit the header row
WithNoTruncation() do not truncate to terminal width (e.g. piping to a file)
WithMaxWidth(n) override terminal-width detection

Machine-readable formats

The same call honours the renderer's format. With output.WithFormat(output.FormatCSV):

Tag,Date,Assets
v1.4.0,2026-07-20,6

Markdown output is safe by construction: a literal | in a cell is backslash-escaped and newlines fold to <br>, so a value can never break out of its cell or open a new row.

Unicode

Column widths and truncation use display width, not byte length, via charmbracelet/x/ansi. CJK, emoji and combining characters align correctly and a truncated cell never splits a rune mid-sequence.