Skip to content

jx:grid

jx:grid fills a rectangular area with header values across columns and data rows downward. Perfect for pivot-style reports, dynamic-column tables, or any report where the columns aren’t known at template design time.

jx:grid(headers="headerList" data="dataRows" lastCell="A1")
AttributeDescriptionRequired
headersExpression for header values (1D slice)Yes
dataExpression for data rows (2D slice)Yes
lastCellBottom-right cell of the grid areaYes

Template:

Template with jx:grid command for dynamic grid generation

Output:

Output showing a filled grid with headers across and data down

Go code:

data := map[string]any{
"headers": []string{"Q1", "Q2", "Q3", "Q4"},
"dataRows": [][]any{
{100, 200, 150, 180},
{90, 110, 130, 160},
},
}

Headers expand to the right. Data rows expand downward. The template cell’s formatting is applied to every generated cell.

  • Use jx:each when your columns are fixed and known at template design time (the common case)
  • Use jx:grid when the number of columns is dynamic — the data determines how many columns appear
  • Shape mismatch. Each row in data (the inner slice) should be the same length as headers. Shorter rows leave blank cells; longer ones overflow past the area boundary.
  • Headers are a 1D slice, data is 2D. headers: []string{"Q1","Q2"} and data: [][]any{{1,2},{3,4}}. Easy to flip when you’re tired.
  • The template cell’s formatting carries to every generated cell. Bold + center-aligned in the template → bold + center in every output cell. Pick the template formatting carefully.
  • Use jx:each for fixed columns. jx:grid is for cases where column count is data-driven; if your columns are known, plain jx:each is clearer.

Download the runnable example: template t09.xlsx | output 09_grid.xlsx | code snippet

Need to insert images into your report?

jx:image →