MCPcopy Index your code
hub / github.com/olekukonko/tablewriter

github.com/olekukonko/tablewriter @v1.1.4 sqlite

repository ↗ · DeepWiki ↗ · release v1.1.4 ↗
1,019 symbols 4,724 edges 62 files 691 documented · 68% 62 cross-repo links
README

TableWriter for Go

Go Go Reference Go Report Card License Benchmarks

tablewriter is a Go library for generating rich text-based tables with support for multiple output formats, including ASCII, Unicode, Markdown, HTML, and colorized terminals. Perfect for CLI tools, logs, and web applications.

Key Features

  • Multi-format rendering: ASCII, Unicode, Markdown, HTML, ANSI-colored
  • Advanced styling: Cell merging, alignment, padding, borders
  • Flexible input: CSV, structs, slices, or streaming data
  • High performance: Minimal allocations, buffer reuse
  • Modern features: Generics support, hierarchical merging, real-time streaming

Installation

Legacy Version (v0.0.5)

For use with legacy applications:

go get github.com/olekukonko/tablewriter@v0.0.5

Latest Version

The latest stable version

go get github.com/olekukonko/tablewriter@v1.1.3

Warning: Version v1.0.0 contains missing functionality and should not be used.

Version Guidance - Legacy: Use v0.0.5 (stable) - New Features: Use @latest (includes generics, super fast streaming APIs) - Legacy Docs: See README_LEGACY.md


Why TableWriter?

  • CLI Ready: Instant compatibility with terminal outputs
  • Database Friendly: Native support for sql.Null* types
  • Secure: Auto-escaping for HTML/Markdown
  • Extensible: Custom renderers and formatters

Quick Example

package main

import (
    "github.com/olekukonko/tablewriter"
    "os"
)

func main() {
    data := [][]string{
        {"Package", "Version", "Status"},
        {"tablewriter", "v0.0.5", "legacy"},
        {"tablewriter", "v1.1.3", "latest"},
    }

    table := tablewriter.NewWriter(os.Stdout)
    table.Header(data[0])
    table.Bulk(data[1:])
    table.Render()
}

Output:

┌─────────────┬─────────┬────────┐
│   PACKAGE   │ VERSION │ STATUS │
├─────────────┼─────────┼────────┤
│ tablewriter │ v0.0.5  │ legacy │
│ tablewriter │ v1.1.3  │ latest │
└─────────────┴─────────┴────────┘

Detailed Usage

Create a table with NewTable or NewWriter, configure it using options or a Config struct, add data with Append or Bulk, and render to an io.Writer. Use renderers like Blueprint (ASCII), HTML, Markdown, Colorized, or Ocean (streaming).

Here's how the API primitives map to the generated ASCII table:

API Call                                  ASCII Table Component
--------                                  ---------------------

table.Header([]string{"NAME", "AGE"})     ┌──────┬─────┐  ← Borders.Top
                                          │ NAME │ AGE │  ← Header row
                                          ├──────┼─────┤  ← Lines.ShowTop (header separator)

table.Append([]string{"Alice", "25"})     │ Alice│ 25  │  ← Data row
                                          ├──────┼─────┤  ← Separators.BetweenRows

table.Append([]string{"Bob", "30"})       │ Bob  │ 30  │  ← Data row
                                          ├──────┼─────┤  ← Lines.ShowBottom (footer separator)

table.Footer([]string{"Total", "2"})      │ Total│ 2   │  ← Footer row
                                          └──────┴─────┘  ← Borders.Bottom

The core components include:

  • Renderer - Implements the core interface for converting table data into output formats. Available renderers include Blueprint (ASCII), HTML, Markdown, Colorized (ASCII with color), Ocean (streaming ASCII), and SVG.

  • Config - The root configuration struct that controls all table behavior and appearance

  • Behavior - Controls high-level rendering behaviors including auto-hiding empty columns, trimming row whitespace, header/footer visibility, and compact mode for optimized merged cell calculations
  • CellConfig - The comprehensive configuration template used for table sections (header, row, footer). Combines formatting, padding, alignment, filtering, callbacks, and width constraints with global and per-column control
  • StreamConfig - Configuration for streaming mode including enable/disable state and strict column validation

  • Rendition - Defines how a renderer formats tables and contains the complete visual styling configuration

  • Borders - Control the outer frame visibility (top, bottom, left, right edges) of the table
  • Lines - Control horizontal boundary lines (above/below headers, above footers) that separate different table sections
  • Separators - Control the visibility of separators between rows and between columns within the table content
  • Symbols - Define the characters used for drawing table borders, corners, and junctions

These components can be configured with various tablewriter.With*() functional options when creating a new table.

Examples

Basic Examples

1. Simple Tables

Create a basic table with headers and rows.

default
package main

import (
    "fmt"
    "github.com/olekukonko/tablewriter"
    "os"
)

type Age int

func (a Age) String() string {
    return fmt.Sprintf("%d yrs", a)
}

func main() {
    data := [][]any{
        {"Alice", Age(25), "New York"},
        {"Bob", Age(30), "Boston"},
    }

    table := tablewriter.NewTable(os.Stdout)
    table.Header("Name", "Age", "City")
    table.Bulk(data)
    table.Render()
}

Output:

┌───────┬────────┬──────────┐
│ NAME  │  AGE   │   CITY   │
├───────┼────────┼──────────┤
│ Alice │ 25 yrs │ New York │
│ Bob   │ 30 yrs │ Boston   │
└───────┴────────┴──────────┘

with customization
package main

import (
    "fmt"
    "github.com/olekukonko/tablewriter"
    "github.com/olekukonko/tablewriter/renderer"
    "github.com/olekukonko/tablewriter/tw"
    "os"
)

type Age int

func (a Age) String() string {
    return fmt.Sprintf("%d yrs", a)
}

func main() {
    data := [][]any{
        {"Alice", Age(25), "New York"},
        {"Bob", Age(30), "Boston"},
    }

    symbols := tw.NewSymbolCustom("Nature").
        WithRow("~").
        WithColumn("|").
        WithTopLeft("🌱").
        WithTopMid("🌿").
        WithTopRight("🌱").
        WithMidLeft("🍃").
        WithCenter("❀").
        WithMidRight("🍃").
        WithBottomLeft("🌻").
        WithBottomMid("🌾").
        WithBottomRight("🌻")

    table := tablewriter.NewTable(os.Stdout, tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{Symbols: symbols})))
    table.Header("Name", "Age", "City")
    table.Bulk(data)
    table.Render()
}
🌱~~~~~~❀~~~~~~~~❀~~~~~~~~~🌱
| NAME  |  AGE   |   CITY   |
🍃~~~~~~❀~~~~~~~~❀~~~~~~~~~🍃
| Alice | 25 yrs | New York |
| Bob   | 30 yrs | Boston   |
🌻~~~~~~❀~~~~~~~~❀~~~~~~~~~🌻

See symbols example for more

2. Markdown Table

Generate a Markdown table for documentation.

package main

import (
    "fmt"
    "github.com/olekukonko/tablewriter"
    "github.com/olekukonko/tablewriter/renderer"
    "os"
    "strings"
    "unicode"
)

type Name struct {
    First string
    Last  string
}

// this will be ignored since  Format() is present
func (n Name) String() string {
    return fmt.Sprintf("%s %s", n.First, n.Last)
}

// Note: Format() overrides String() if both exist.
func (n Name) Format() string {
    return fmt.Sprintf("%s %s", n.clean(n.First), n.clean(n.Last))
}

// clean ensures the first letter is capitalized and the rest are lowercase
func (n Name) clean(s string) string {
    s = strings.TrimSpace(strings.ToLower(s))
    words := strings.Fields(s)
    s = strings.Join(words, "")

    if s == "" {
        return s
    }
    // Capitalize the first letter
    runes := []rune(s)
    runes[0] = unicode.ToUpper(runes[0])
    return string(runes)
}

type Age int

// Age int will be ignore and string will be used
func (a Age) String() string {
    return fmt.Sprintf("%d yrs", a)
}

func main() {
    data := [][]any{
        {Name{"Al  i  CE", " Ma  SK"}, Age(25), "New York"},
        {Name{"bOb", "mar   le   y"}, Age(30), "Boston"},
    }

    table := tablewriter.NewTable(os.Stdout,
        tablewriter.WithRenderer(renderer.NewMarkdown()),
    )

    table.Header([]string{"Name", "Age", "City"})
    table.Bulk(data)
    table.Render()
}

Output:

|    NAME    |  AGE   |   CITY   |
|:----------:|:------:|:--------:|
| Alice Mask | 25 yrs | New York |
| Bob Marley | 30 yrs | Boston   |


3. CSV Input

Create a table from a CSV file with custom row alignment.

package main

import (
    "github.com/olekukonko/tablewriter"
    "github.com/olekukonko/tablewriter/tw"
    "log"
    "os"
)

func main() {
    // Assuming "test.csv" contains: "First Name,Last Name,SSN\nJohn,Barry,123456\nKathy,Smith,687987"
    table, err := tablewriter.NewCSV(os.Stdout, "test.csv", true)
    if err != nil {
        log.Fatalf("Error: %v", err)
    }

    table.Configure(func(config *tablewriter.Config) {
        config.Row.Alignment.Global = tw.AlignLeft
    })
    table.Render()
}

Output:

┌────────────┬───────────┬─────────┐
│ FIRST NAME │ LAST NAME │   SSN   │
├────────────┼───────────┼─────────┤
│ John       │ Barry     │ 123456  │
│ Kathy      │ Smith     │ 687987  │
└────────────┴───────────┴─────────┘

Advanced Examples

4. Colorized Table with Long Values

Create a colorized table with wrapped long values, per-column colors, and a styled footer (inspired by TestColorizedLongValues and TestColorizedCustomColors).

package main

import (
    "github.com/fatih/color"
    "github.com/olekukonko/tablewriter"
    "github.com/olekukonko/tablewriter/renderer"
    "github.com/olekukonko/tablewriter/tw"
    "os"
)

func main() {
    data := [][]string{
        {"1", "This is a very long description that needs wrapping for readability", "OK"},
        {"2", "Short description", "DONE"},
        {"3", "Another lengthy description requiring truncation or wrapping", "ERROR"},
    }

    // Configure colors: green headers, cyan/magenta rows, yellow footer
    colorCfg := renderer.ColorizedConfig{
        Header: renderer.Tint{
            FG: renderer.Colors{color.FgGreen, color.Bold}, // Green bold headers
            BG: renderer.Colors{color.BgHiWhite},
        },
        Column: renderer.Tint{
            FG: renderer.Colors{color.FgCyan}, // Default cyan for rows
            Columns: []renderer.Tint{
                {FG: renderer.Colors{color.FgMagenta}}, // Magenta for column 0
                {},                                     // Inherit default (cyan)
                {FG: renderer.Colors{color.FgHiRed}},   // High-intensity red for column 2
            },
        },
        Footer: renderer.Tint{
            FG: renderer.Colors{color.FgYellow, color.Bold}, // Yellow bold footer
            Columns: []renderer.Tint{
                {},                                      // Inherit default
                {FG: renderer.Colors{color.FgHiYellow}}, // High-intensity yellow for column 1
                {},                                      // Inherit default
            },
        },
        Border:    renderer.Tint{FG: renderer.Colors{color.FgWhite}}, // White borders
        Separator: renderer.Tint{FG: renderer.Colors{color.FgWhite}}, // White separators
    }

    table := tablewriter.NewTable(os.Stdout,
        tablewriter.WithRenderer(renderer.NewColorized(colorCfg)),
        tablewriter.WithConfig(tablewriter.Config{
            Row: tw.CellConfig{
                Formatting:   tw.CellFormatting{AutoWrap: tw.WrapNormal}, // Wrap long content
                Alignment:    tw.CellAlignment{Global: tw.AlignLeft},     // Left-align rows
                ColMaxWidths: tw.CellWidth{Global: 25},
            },
            Footer: tw.CellConfig{
                Alignment: tw.CellAlignment{Global: tw.AlignRight},
            },
        }),
    )

    table.Header([]string{"ID", "Description", "Status"})
    table.Bulk(data)
    table.Footer([]string{"", "Total", "3"})
    table.Render()
}

Output (colors visible in ANSI-compatible terminals):

Colorized Table with Long Values

5. Streaming Table with Truncation

Stream a table incrementally with truncation and a footer, simulating a real-time data feed (inspired by TestOceanStreamTruncation and TestOceanStreamSlowOutput).

package main

import (
    "github.com/olekukonko/tablewriter"
    "github.com/olekukonko/tablewriter/tw"
    "log"
    "os"
    "time"
)

func main() {
    table := tablewriter.NewTable(os.Stdout, tablewriter.WithStreaming(tw.StreamConfig{Enable: true}))

    // Start streaming
    if err := table.Start(); err != nil {
        log.Fatalf("Start failed: %v", err)
    }

    defer table.Close()

    // Stream header
    table.Header([]string{"ID", "Description", "Status"})

    // Stream rows with simulated delay
    data := [][]string{
        {"1", "This description is too long", "OK"},
        {"2", "Short desc", "DONE"},
        {"3", "Another long description here", "ERROR"},
    }
    for _, row := range data {
        table.Append(row)
        time.Sleep(500 * time.Millisecond) // Simulate real-time data feed
    }

    // Stream footer
    table.Footer([]string{"", "Total", "3"})
}

Output (appears incrementally):

┌────────┬───────────────┬──────────┐
│   ID   │  DESCRIPTION  │  STATUS  │
├────────┼───────────────┼──────────┤
│ 1      │ This          │ OK       │
│        │ description   │          │
│        │ is too long   │          │
│ 2      │ Short desc    │ DONE     │
│ 3      │ Another long  │ ERROR    │
│        │ description   │          │
│        │ here          │          │
├────────┼───────────────┼──────────┤
│        │         Total │        3 │
└────────┴───────────────┴──────────┘

Note: Long descriptions are truncated with due to fixed column widths. The output appears row-by-row, simulating a real-time feed.

6. Hierarchical Merging for Organizational Data

Show hierarchical merging for a tree-like structure, such as an organizational hierarchy (inspired by TestMergeHierarchicalUnicode).

```go package main

import ( "github.com/olekukonko/

Extension points exported contracts — how you extend this code

Renderer (Interface)
Renderer defines the interface for rendering tables to an io.Writer. Implementations must handle headers, rows, footers, [6 …
tw/renderer.go
Symbols (Interface)
Symbols defines the interface for table border symbols [8 implementers]
tw/symbols.go
Counter (Interface)
Counter defines an interface that combines io.Writer with a method to retrieve a total. This is used by the WithCounter [2 …
tw/types.go
Option (FuncType)
Option defines a function type for configuring a Table instance.
option.go
EvictCallback (FuncType)
EvictCallback is a function called when an entry is evicted. This includes evictions during Purge or Resize operations.
pkg/twcache/lru.go
Renditioning (Interface)
Renditioning has a method to update its rendition. Let's define an optional interface for this. [3 implementers]
tw/renderer.go
Formatter (Interface)
Formatter defines an interface for types that can format themselves into a string. Used for custom formatting of table c [1 …
tw/types.go
Cache (Interface)
Cache defines a generic interface for a key-value storage with type constraints on keys and values. The keys must be of
pkg/twcache/cache.go

Core symbols most depended-on inside this repo

String
called by 240
tests/fn.go
Append
called by 229
tablewriter.go
NewTable
called by 159
tablewriter.go
Render
called by 152
tablewriter.go
Header
called by 137
tablewriter.go
visualCheck
called by 122
tests/fn.go
Debug
called by 118
tablewriter.go
Debug
called by 115
renderer/svg.go

Shape

Method 534
Function 355
Struct 101
TypeAlias 20
Interface 6
FuncType 3

Languages

Go100%

Modules by API surface

config.go145 symbols
tw/deprecated.go96 symbols
tw/symbols.go70 symbols
option.go63 symbols
tablewriter.go43 symbols
tw/types.go34 symbols
zoo.go23 symbols
tw/renderer.go23 symbols
renderer/svg.go22 symbols
tw/mapper.go21 symbols
pkg/twwidth/tab.go21 symbols
tw/slicer.go18 symbols

Dependencies from manifests, versioned

github.com/cespare/xxhash/v2v2.3.0 · 1×
github.com/clipperhouse/displaywidthv0.10.0 · 1×
github.com/clipperhouse/uax29/v2v2.6.0 · 1×
github.com/mattn/go-colorablev0.1.14 · 1×
github.com/mattn/go-isattyv0.0.20 · 1×
github.com/mattn/go-runewidthv0.0.19 · 1×
github.com/olekukonko/catv0.0.0-2025091110415 · 1×
github.com/olekukonko/errorsv1.2.0 · 1×
github.com/olekukonko/llv0.1.6 · 1×
github.com/olekukonko/tsv0.0.0-2017100211525 · 1×
golang.org/x/sysv0.30.0 · 1×

For agents

$ claude mcp add tablewriter \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact