README.md
1ASCII Table Writer
2=========
3
4[![Build Status](https://travis-ci.org/olekukonko/tablewriter.png?branch=master)](https://travis-ci.org/olekukonko/tablewriter)
5[![Total views](https://img.shields.io/sourcegraph/rrc/github.com/olekukonko/tablewriter.svg)](https://sourcegraph.com/github.com/olekukonko/tablewriter)
6[![Godoc](https://godoc.org/github.com/olekukonko/tablewriter?status.svg)](https://godoc.org/github.com/olekukonko/tablewriter)
7
8Generate ASCII table on the fly ... Installation is simple as
9
10 go get github.com/olekukonko/tablewriter
11
12
13#### Features
14- Automatic Padding
15- Support Multiple Lines
16- Supports Alignment
17- Support Custom Separators
18- Automatic Alignment of numbers & percentage
19- Write directly to http , file etc via `io.Writer`
20- Read directly from CSV file
21- Optional row line via `SetRowLine`
22- Normalise table header
23- Make CSV Headers optional
24- Enable or disable table border
25- Set custom footer support
26- Optional identical cells merging
27- Set custom caption
28- Optional reflowing of paragrpahs in multi-line cells.
29
30#### Example 1 - Basic
31```go
32data := [][]string{
33 []string{"A", "The Good", "500"},
34 []string{"B", "The Very very Bad Man", "288"},
35 []string{"C", "The Ugly", "120"},
36 []string{"D", "The Gopher", "800"},
37}
38
39table := tablewriter.NewWriter(os.Stdout)
40table.SetHeader([]string{"Name", "Sign", "Rating"})
41
42for _, v := range data {
43 table.Append(v)
44}
45table.Render() // Send output
46```
47
48##### Output 1
49```
50+------+-----------------------+--------+
51| NAME | SIGN | RATING |
52+------+-----------------------+--------+
53| A | The Good | 500 |
54| B | The Very very Bad Man | 288 |
55| C | The Ugly | 120 |
56| D | The Gopher | 800 |
57+------+-----------------------+--------+
58```
59
60#### Example 2 - Without Border / Footer / Bulk Append
61```go
62data := [][]string{
63 []string{"1/1/2014", "Domain name", "2233", "$10.98"},
64 []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
65 []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
66 []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
67}
68
69table := tablewriter.NewWriter(os.Stdout)
70table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
71table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
72table.SetBorder(false) // Set Border to false
73table.AppendBulk(data) // Add Bulk Data
74table.Render()
75```
76
77##### Output 2
78```
79
80 DATE | DESCRIPTION | CV2 | AMOUNT
81-----------+--------------------------+-------+----------
82 1/1/2014 | Domain name | 2233 | $10.98
83 1/1/2014 | January Hosting | 2233 | $54.95
84 1/4/2014 | February Hosting | 2233 | $51.00
85 1/4/2014 | February Extra Bandwidth | 2233 | $30.00
86-----------+--------------------------+-------+----------
87 TOTAL | $146 93
88 --------+----------
89
90```
91
92
93#### Example 3 - CSV
94```go
95table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test_info.csv", true)
96table.SetAlignment(tablewriter.ALIGN_LEFT) // Set Alignment
97table.Render()
98```
99
100##### Output 3
101```
102+----------+--------------+------+-----+---------+----------------+
103| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA |
104+----------+--------------+------+-----+---------+----------------+
105| user_id | smallint(5) | NO | PRI | NULL | auto_increment |
106| username | varchar(10) | NO | | NULL | |
107| password | varchar(100) | NO | | NULL | |
108+----------+--------------+------+-----+---------+----------------+
109```
110
111#### Example 4 - Custom Separator
112```go
113table, _ := tablewriter.NewCSV(os.Stdout, "testdata/test.csv", true)
114table.SetRowLine(true) // Enable row line
115
116// Change table lines
117table.SetCenterSeparator("*")
118table.SetColumnSeparator("╪")
119table.SetRowSeparator("-")
120
121table.SetAlignment(tablewriter.ALIGN_LEFT)
122table.Render()
123```
124
125##### Output 4
126```
127*------------*-----------*---------*
128╪ FIRST NAME ╪ LAST NAME ╪ SSN ╪
129*------------*-----------*---------*
130╪ John ╪ Barry ╪ 123456 ╪
131*------------*-----------*---------*
132╪ Kathy ╪ Smith ╪ 687987 ╪
133*------------*-----------*---------*
134╪ Bob ╪ McCornick ╪ 3979870 ╪
135*------------*-----------*---------*
136```
137
138#### Example 5 - Markdown Format
139```go
140data := [][]string{
141 []string{"1/1/2014", "Domain name", "2233", "$10.98"},
142 []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
143 []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
144 []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
145}
146
147table := tablewriter.NewWriter(os.Stdout)
148table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
149table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
150table.SetCenterSeparator("|")
151table.AppendBulk(data) // Add Bulk Data
152table.Render()
153```
154
155##### Output 5
156```
157| DATE | DESCRIPTION | CV2 | AMOUNT |
158|----------|--------------------------|------|--------|
159| 1/1/2014 | Domain name | 2233 | $10.98 |
160| 1/1/2014 | January Hosting | 2233 | $54.95 |
161| 1/4/2014 | February Hosting | 2233 | $51.00 |
162| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 |
163```
164
165#### Example 6 - Identical cells merging
166```go
167data := [][]string{
168 []string{"1/1/2014", "Domain name", "1234", "$10.98"},
169 []string{"1/1/2014", "January Hosting", "2345", "$54.95"},
170 []string{"1/4/2014", "February Hosting", "3456", "$51.00"},
171 []string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"},
172}
173
174table := tablewriter.NewWriter(os.Stdout)
175table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
176table.SetFooter([]string{"", "", "Total", "$146.93"})
177table.SetAutoMergeCells(true)
178table.SetRowLine(true)
179table.AppendBulk(data)
180table.Render()
181```
182
183##### Output 6
184```
185+----------+--------------------------+-------+---------+
186| DATE | DESCRIPTION | CV2 | AMOUNT |
187+----------+--------------------------+-------+---------+
188| 1/1/2014 | Domain name | 1234 | $10.98 |
189+ +--------------------------+-------+---------+
190| | January Hosting | 2345 | $54.95 |
191+----------+--------------------------+-------+---------+
192| 1/4/2014 | February Hosting | 3456 | $51.00 |
193+ +--------------------------+-------+---------+
194| | February Extra Bandwidth | 4567 | $30.00 |
195+----------+--------------------------+-------+---------+
196| TOTAL | $146 93 |
197+----------+--------------------------+-------+---------+
198```
199
200
201#### Table with color
202```go
203data := [][]string{
204 []string{"1/1/2014", "Domain name", "2233", "$10.98"},
205 []string{"1/1/2014", "January Hosting", "2233", "$54.95"},
206 []string{"1/4/2014", "February Hosting", "2233", "$51.00"},
207 []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"},
208}
209
210table := tablewriter.NewWriter(os.Stdout)
211table.SetHeader([]string{"Date", "Description", "CV2", "Amount"})
212table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer
213table.SetBorder(false) // Set Border to false
214
215table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor},
216 tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor},
217 tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor},
218 tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor})
219
220table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
221 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor},
222 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
223 tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor})
224
225table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{},
226 tablewriter.Colors{tablewriter.Bold},
227 tablewriter.Colors{tablewriter.FgHiRedColor})
228
229table.AppendBulk(data)
230table.Render()
231```
232
233#### Table with color Output
234![Table with Color](https://cloud.githubusercontent.com/assets/6460392/21101956/bbc7b356-c0a1-11e6-9f36-dba694746efc.png)
235
236#### Example - 7 Table Cells with Color
237
238Individual Cell Colors from `func Rich` take precedence over Column Colors
239
240```go
241data := [][]string{
242 []string{"Test1Merge", "HelloCol2 - 1", "HelloCol3 - 1", "HelloCol4 - 1"},
243 []string{"Test1Merge", "HelloCol2 - 2", "HelloCol3 - 2", "HelloCol4 - 2"},
244 []string{"Test1Merge", "HelloCol2 - 3", "HelloCol3 - 3", "HelloCol4 - 3"},
245 []string{"Test2Merge", "HelloCol2 - 4", "HelloCol3 - 4", "HelloCol4 - 4"},
246 []string{"Test2Merge", "HelloCol2 - 5", "HelloCol3 - 5", "HelloCol4 - 5"},
247 []string{"Test2Merge", "HelloCol2 - 6", "HelloCol3 - 6", "HelloCol4 - 6"},
248 []string{"Test2Merge", "HelloCol2 - 7", "HelloCol3 - 7", "HelloCol4 - 7"},
249 []string{"Test3Merge", "HelloCol2 - 8", "HelloCol3 - 8", "HelloCol4 - 8"},
250 []string{"Test3Merge", "HelloCol2 - 9", "HelloCol3 - 9", "HelloCol4 - 9"},
251 []string{"Test3Merge", "HelloCol2 - 10", "HelloCol3 -10", "HelloCol4 - 10"},
252}
253
254table := tablewriter.NewWriter(os.Stdout)
255table.SetHeader([]string{"Col1", "Col2", "Col3", "Col4"})
256table.SetFooter([]string{"", "", "Footer3", "Footer4"})
257table.SetBorder(false)
258
259table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor},
260 tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor},
261 tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor},
262 tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor})
263
264table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
265 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor},
266 tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor},
267 tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor})
268
269table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{},
270 tablewriter.Colors{tablewriter.Bold},
271 tablewriter.Colors{tablewriter.FgHiRedColor})
272
273colorData1 := []string{"TestCOLOR1Merge", "HelloCol2 - COLOR1", "HelloCol3 - COLOR1", "HelloCol4 - COLOR1"}
274colorData2 := []string{"TestCOLOR2Merge", "HelloCol2 - COLOR2", "HelloCol3 - COLOR2", "HelloCol4 - COLOR2"}
275
276for i, row := range data {
277 if i == 4 {
278 table.Rich(colorData1, []tablewriter.Colors{tablewriter.Colors{}, tablewriter.Colors{tablewriter.Normal, tablewriter.FgCyanColor}, tablewriter.Colors{tablewriter.Bold, tablewriter.FgWhiteColor}, tablewriter.Colors{}})
279 table.Rich(colorData2, []tablewriter.Colors{tablewriter.Colors{tablewriter.Normal, tablewriter.FgMagentaColor}, tablewriter.Colors{}, tablewriter.Colors{tablewriter.Bold, tablewriter.BgRedColor}, tablewriter.Colors{tablewriter.FgHiGreenColor, tablewriter.Italic, tablewriter.BgHiCyanColor}})
280 }
281 table.Append(row)
282}
283
284table.SetAutoMergeCells(true)
285table.Render()
286
287```
288
289##### Table cells with color Output
290![Table cells with Color](https://user-images.githubusercontent.com/9064687/63969376-bcd88d80-ca6f-11e9-9466-c3d954700b25.png)
291
292#### Example 8 - Set table caption
293```go
294data := [][]string{
295 []string{"A", "The Good", "500"},
296 []string{"B", "The Very very Bad Man", "288"},
297 []string{"C", "The Ugly", "120"},
298 []string{"D", "The Gopher", "800"},
299}
300
301table := tablewriter.NewWriter(os.Stdout)
302table.SetHeader([]string{"Name", "Sign", "Rating"})
303table.SetCaption(true, "Movie ratings.")
304
305for _, v := range data {
306 table.Append(v)
307}
308table.Render() // Send output
309```
310
311Note: Caption text will wrap with total width of rendered table.
312
313##### Output 7
314```
315+------+-----------------------+--------+
316| NAME | SIGN | RATING |
317+------+-----------------------+--------+
318| A | The Good | 500 |
319| B | The Very very Bad Man | 288 |
320| C | The Ugly | 120 |
321| D | The Gopher | 800 |
322+------+-----------------------+--------+
323Movie ratings.
324```
325
326#### Example 8 - Set NoWhiteSpace and TablePadding option
327```go
328data := [][]string{
329 {"node1.example.com", "Ready", "compute", "1.11"},
330 {"node2.example.com", "Ready", "compute", "1.11"},
331 {"node3.example.com", "Ready", "compute", "1.11"},
332 {"node4.example.com", "NotReady", "compute", "1.11"},
333}
334
335table := tablewriter.NewWriter(os.Stdout)
336table.SetHeader([]string{"Name", "Status", "Role", "Version"})
337table.SetAutoWrapText(false)
338table.SetAutoFormatHeaders(true)
339table.SetHeaderAlignment(ALIGN_LEFT)
340table.SetAlignment(ALIGN_LEFT)
341table.SetCenterSeparator("")
342table.SetColumnSeparator("")
343table.SetRowSeparator("")
344table.SetHeaderLine(false)
345table.SetBorder(false)
346table.SetTablePadding("\t") // pad with tabs
347table.SetNoWhiteSpace(true)
348table.AppendBulk(data) // Add Bulk Data
349table.Render()
350```
351
352##### Output 8
353```
354NAME STATUS ROLE VERSION
355node1.example.com Ready compute 1.11
356node2.example.com Ready compute 1.11
357node3.example.com Ready compute 1.11
358node4.example.com NotReady compute 1.11
359```
360
361#### Render table into a string
362
363Instead of rendering the table to `io.Stdout` you can also render it into a string. Go 1.10 introduced the `strings.Builder` type which implements the `io.Writer` interface and can therefore be used for this task. Example:
364
365```go
366package main
367
368import (
369 "strings"
370 "fmt"
371
372 "github.com/olekukonko/tablewriter"
373)
374
375func main() {
376 tableString := &strings.Builder{}
377 table := tablewriter.NewWriter(tableString)
378
379 /*
380 * Code to fill the table
381 */
382
383 table.Render()
384
385 fmt.Println(tableString.String())
386}
387```
388
389#### TODO
390- ~~Import Directly from CSV~~ - `done`
391- ~~Support for `SetFooter`~~ - `done`
392- ~~Support for `SetBorder`~~ - `done`
393- ~~Support table with uneven rows~~ - `done`
394- ~~Support custom alignment~~
395- General Improvement & Optimisation
396- `NewHTML` Parse table from HTML
397