[{"data":1,"prerenderedAt":1756},["ShallowReactive",2],{"blog-en-zebra-striped-table-rows":3},{"id":4,"title":5,"author":6,"body":10,"date":1727,"description":1728,"draft":1729,"extension":1730,"howTo":1731,"image":1746,"meta":1747,"navigation":132,"path":1748,"seo":1749,"stem":1750,"tags":1751,"updated":1746,"__hash__":1755},"blog/blog/019.zebra-striped-table-rows.md","How do I create striped (zebra) table rows?",{"name":7,"url":8,"avatar":9},"Taiki Noda","https://nadai.dev/en/about","https://nadai.dev/og-default.png",{"type":11,"value":12,"toc":1716},"minimark",[13,18,35,39,106,109,113,1144,1150,1154,1165,1244,1247,1250,1254,1261,1338,1341,1352,1356,1363,1577,1580,1589,1593,1646,1650,1676,1680,1683,1700,1712],[14,15,17],"h2",{"id":16},"the-question-in-other-words","The question, in other words",[19,20,21,22,26,27,34],"p",{},"I have a table — invoices, transactions, log lines, anything with more than 5 rows — and I want every other row tinted gray so the eye can track across without losing the line. Bootstrap calls it ",[23,24,25],"code",{},".table-striped",". I just want that, in ",[28,29,33],"a",{"href":30,"rel":31},"https://github.com/gpdf-dev/gpdf",[32],"nofollow","gpdf",", without writing a row loop.",[14,36,38],{"id":37},"tldr","TL;DR",[40,41,46],"pre",{"className":42,"code":43,"language":44,"meta":45,"style":45},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","c.Table(header, rows, template.TableStripe(pdf.RGBHex(0xF5F5F5)))\n","go","",[23,47,48],{"__ignoreMap":45},[49,50,53,57,61,65,68,71,74,77,79,82,84,87,89,92,94,97,99,103],"span",{"class":51,"line":52},"line",1,[49,54,56],{"class":55},"sTEyZ","c",[49,58,60],{"class":59},"sMK4o",".",[49,62,64],{"class":63},"s2Zo4","Table",[49,66,67],{"class":59},"(",[49,69,70],{"class":55},"header",[49,72,73],{"class":59},",",[49,75,76],{"class":55}," rows",[49,78,73],{"class":59},[49,80,81],{"class":55}," template",[49,83,60],{"class":59},[49,85,86],{"class":63},"TableStripe",[49,88,67],{"class":59},[49,90,91],{"class":55},"pdf",[49,93,60],{"class":59},[49,95,96],{"class":63},"RGBHex",[49,98,67],{"class":59},[49,100,102],{"class":101},"sbssI","0xF5F5F5",[49,104,105],{"class":59},")))\n",[19,107,108],{},"That's it. gpdf handles the alternation. The header is excluded — only body rows are striped. The first body row stays plain; the second is tinted; the third plain; the fourth tinted; and so on.",[14,110,112],{"id":111},"working-code","Working code",[40,114,116],{"className":42,"code":115,"language":44,"meta":45,"style":45},"package main\n\nimport (\n    \"log\"\n    \"os\"\n\n    \"github.com/gpdf-dev/gpdf\"\n    \"github.com/gpdf-dev/gpdf/document\"\n    \"github.com/gpdf-dev/gpdf/pdf\"\n    \"github.com/gpdf-dev/gpdf/template\"\n)\n\nfunc main() {\n    doc := gpdf.NewDocument(\n        gpdf.WithPageSize(gpdf.A4),\n        gpdf.WithMargins(document.UniformEdges(document.Mm(20))),\n    )\n\n    brand := pdf.RGBHex(0x1A237E)     // header background\n    stripe := pdf.RGBHex(0xF5F5F5)    // every-other-row tint\n\n    page := doc.AddPage()\n    page.AutoRow(func(r *template.RowBuilder) {\n        r.Col(12, func(c *template.ColBuilder) {\n            c.Text(\"Q1 Sales\", template.FontSize(20), template.Bold())\n            c.Spacer(document.Mm(4))\n\n            c.Table(\n                []string{\"Product\", \"Region\", \"Qty\", \"Revenue\"},\n                [][]string{\n                    {\"Laptop Pro 15\", \"NA\",   \"120\", \"$155,880\"},\n                    {\"Wireless Mouse\", \"EU\",  \"640\", \"$19,193\"},\n                    {\"USB-C Hub\",      \"APAC\",\"410\", \"$20,495\"},\n                    {\"Monitor 27\\\"\",   \"NA\",  \"180\", \"$71,820\"},\n                    {\"Keyboard\",       \"EU\",  \"320\", \"$25,596\"},\n                    {\"Webcam HD\",      \"APAC\",\"260\", \"$23,397\"},\n                },\n                template.ColumnWidths(40, 20, 15, 25),\n                template.TableHeaderStyle(\n                    template.TextColor(pdf.White),\n                    template.BgColor(brand),\n                ),\n                template.TableStripe(stripe),\n            )\n        })\n    })\n\n    data, err := doc.Generate()\n    if err != nil {\n        log.Fatal(err)\n    }\n    if err := os.WriteFile(\"sales.pdf\", data, 0o644); err != nil {\n        log.Fatal(err)\n    }\n}\n",[23,117,118,127,134,144,156,166,171,181,191,201,211,217,222,237,257,280,317,323,328,355,378,383,402,435,471,519,545,550,561,612,623,666,708,750,793,834,874,880,913,925,947,964,970,986,992,998,1004,1009,1031,1047,1065,1071,1118,1133,1138],{"__ignoreMap":45},[49,119,120,123],{"class":51,"line":52},[49,121,122],{"class":59},"package",[49,124,126],{"class":125},"sBMFI"," main\n",[49,128,130],{"class":51,"line":129},2,[49,131,133],{"emptyLinePlaceholder":132},true,"\n",[49,135,137,141],{"class":51,"line":136},3,[49,138,140],{"class":139},"s7zQu","import",[49,142,143],{"class":59}," (\n",[49,145,147,150,153],{"class":51,"line":146},4,[49,148,149],{"class":59},"    \"",[49,151,152],{"class":125},"log",[49,154,155],{"class":59},"\"\n",[49,157,159,161,164],{"class":51,"line":158},5,[49,160,149],{"class":59},[49,162,163],{"class":125},"os",[49,165,155],{"class":59},[49,167,169],{"class":51,"line":168},6,[49,170,133],{"emptyLinePlaceholder":132},[49,172,174,176,179],{"class":51,"line":173},7,[49,175,149],{"class":59},[49,177,178],{"class":125},"github.com/gpdf-dev/gpdf",[49,180,155],{"class":59},[49,182,184,186,189],{"class":51,"line":183},8,[49,185,149],{"class":59},[49,187,188],{"class":125},"github.com/gpdf-dev/gpdf/document",[49,190,155],{"class":59},[49,192,194,196,199],{"class":51,"line":193},9,[49,195,149],{"class":59},[49,197,198],{"class":125},"github.com/gpdf-dev/gpdf/pdf",[49,200,155],{"class":59},[49,202,204,206,209],{"class":51,"line":203},10,[49,205,149],{"class":59},[49,207,208],{"class":125},"github.com/gpdf-dev/gpdf/template",[49,210,155],{"class":59},[49,212,214],{"class":51,"line":213},11,[49,215,216],{"class":59},")\n",[49,218,220],{"class":51,"line":219},12,[49,221,133],{"emptyLinePlaceholder":132},[49,223,225,228,231,234],{"class":51,"line":224},13,[49,226,227],{"class":59},"func",[49,229,230],{"class":63}," main",[49,232,233],{"class":59},"()",[49,235,236],{"class":59}," {\n",[49,238,240,243,246,249,251,254],{"class":51,"line":239},14,[49,241,242],{"class":55},"    doc ",[49,244,245],{"class":59},":=",[49,247,248],{"class":55}," gpdf",[49,250,60],{"class":59},[49,252,253],{"class":63},"NewDocument",[49,255,256],{"class":59},"(\n",[49,258,260,263,265,268,270,272,274,277],{"class":51,"line":259},15,[49,261,262],{"class":55},"        gpdf",[49,264,60],{"class":59},[49,266,267],{"class":63},"WithPageSize",[49,269,67],{"class":59},[49,271,33],{"class":55},[49,273,60],{"class":59},[49,275,276],{"class":55},"A4",[49,278,279],{"class":59},"),\n",[49,281,283,285,287,290,292,295,297,300,302,304,306,309,311,314],{"class":51,"line":282},16,[49,284,262],{"class":55},[49,286,60],{"class":59},[49,288,289],{"class":63},"WithMargins",[49,291,67],{"class":59},[49,293,294],{"class":55},"document",[49,296,60],{"class":59},[49,298,299],{"class":63},"UniformEdges",[49,301,67],{"class":59},[49,303,294],{"class":55},[49,305,60],{"class":59},[49,307,308],{"class":63},"Mm",[49,310,67],{"class":59},[49,312,313],{"class":101},"20",[49,315,316],{"class":59},"))),\n",[49,318,320],{"class":51,"line":319},17,[49,321,322],{"class":59},"    )\n",[49,324,326],{"class":51,"line":325},18,[49,327,133],{"emptyLinePlaceholder":132},[49,329,331,334,336,339,341,343,345,348,351],{"class":51,"line":330},19,[49,332,333],{"class":55},"    brand ",[49,335,245],{"class":59},[49,337,338],{"class":55}," pdf",[49,340,60],{"class":59},[49,342,96],{"class":63},[49,344,67],{"class":59},[49,346,347],{"class":101},"0x1A237E",[49,349,350],{"class":59},")",[49,352,354],{"class":353},"sHwdD","     // header background\n",[49,356,358,361,363,365,367,369,371,373,375],{"class":51,"line":357},20,[49,359,360],{"class":55},"    stripe ",[49,362,245],{"class":59},[49,364,338],{"class":55},[49,366,60],{"class":59},[49,368,96],{"class":63},[49,370,67],{"class":59},[49,372,102],{"class":101},[49,374,350],{"class":59},[49,376,377],{"class":353},"    // every-other-row tint\n",[49,379,381],{"class":51,"line":380},21,[49,382,133],{"emptyLinePlaceholder":132},[49,384,386,389,391,394,396,399],{"class":51,"line":385},22,[49,387,388],{"class":55},"    page ",[49,390,245],{"class":59},[49,392,393],{"class":55}," doc",[49,395,60],{"class":59},[49,397,398],{"class":63},"AddPage",[49,400,401],{"class":59},"()\n",[49,403,405,408,410,413,416,420,423,426,428,431,433],{"class":51,"line":404},23,[49,406,407],{"class":55},"    page",[49,409,60],{"class":59},[49,411,412],{"class":63},"AutoRow",[49,414,415],{"class":59},"(func(",[49,417,419],{"class":418},"sHdIc","r",[49,421,422],{"class":59}," *",[49,424,425],{"class":125},"template",[49,427,60],{"class":59},[49,429,430],{"class":125},"RowBuilder",[49,432,350],{"class":59},[49,434,236],{"class":59},[49,436,438,441,443,446,448,451,453,456,458,460,462,464,467,469],{"class":51,"line":437},24,[49,439,440],{"class":55},"        r",[49,442,60],{"class":59},[49,444,445],{"class":63},"Col",[49,447,67],{"class":59},[49,449,450],{"class":101},"12",[49,452,73],{"class":59},[49,454,455],{"class":59}," func(",[49,457,56],{"class":418},[49,459,422],{"class":59},[49,461,425],{"class":125},[49,463,60],{"class":59},[49,465,466],{"class":125},"ColBuilder",[49,468,350],{"class":59},[49,470,236],{"class":59},[49,472,474,477,479,482,484,487,491,493,495,497,499,502,504,506,509,511,513,516],{"class":51,"line":473},25,[49,475,476],{"class":55},"            c",[49,478,60],{"class":59},[49,480,481],{"class":63},"Text",[49,483,67],{"class":59},[49,485,486],{"class":59},"\"",[49,488,490],{"class":489},"sfazB","Q1 Sales",[49,492,486],{"class":59},[49,494,73],{"class":59},[49,496,81],{"class":55},[49,498,60],{"class":59},[49,500,501],{"class":63},"FontSize",[49,503,67],{"class":59},[49,505,313],{"class":101},[49,507,508],{"class":59},"),",[49,510,81],{"class":55},[49,512,60],{"class":59},[49,514,515],{"class":63},"Bold",[49,517,518],{"class":59},"())\n",[49,520,522,524,526,529,531,533,535,537,539,542],{"class":51,"line":521},26,[49,523,476],{"class":55},[49,525,60],{"class":59},[49,527,528],{"class":63},"Spacer",[49,530,67],{"class":59},[49,532,294],{"class":55},[49,534,60],{"class":59},[49,536,308],{"class":63},[49,538,67],{"class":59},[49,540,541],{"class":101},"4",[49,543,544],{"class":59},"))\n",[49,546,548],{"class":51,"line":547},27,[49,549,133],{"emptyLinePlaceholder":132},[49,551,553,555,557,559],{"class":51,"line":552},28,[49,554,476],{"class":55},[49,556,60],{"class":59},[49,558,64],{"class":63},[49,560,256],{"class":59},[49,562,564,567,571,574,576,579,581,583,586,589,591,593,595,598,600,602,604,607,609],{"class":51,"line":563},29,[49,565,566],{"class":59},"                []",[49,568,570],{"class":569},"spNyl","string",[49,572,573],{"class":59},"{",[49,575,486],{"class":59},[49,577,578],{"class":489},"Product",[49,580,486],{"class":59},[49,582,73],{"class":59},[49,584,585],{"class":59}," \"",[49,587,588],{"class":489},"Region",[49,590,486],{"class":59},[49,592,73],{"class":59},[49,594,585],{"class":59},[49,596,597],{"class":489},"Qty",[49,599,486],{"class":59},[49,601,73],{"class":59},[49,603,585],{"class":59},[49,605,606],{"class":489},"Revenue",[49,608,486],{"class":59},[49,610,611],{"class":59},"},\n",[49,613,615,618,620],{"class":51,"line":614},30,[49,616,617],{"class":59},"                [][]",[49,619,570],{"class":569},[49,621,622],{"class":59},"{\n",[49,624,626,629,631,634,636,638,640,643,645,647,650,653,655,657,659,662,664],{"class":51,"line":625},31,[49,627,628],{"class":59},"                    {",[49,630,486],{"class":59},[49,632,633],{"class":489},"Laptop Pro 15",[49,635,486],{"class":59},[49,637,73],{"class":59},[49,639,585],{"class":59},[49,641,642],{"class":489},"NA",[49,644,486],{"class":59},[49,646,73],{"class":59},[49,648,649],{"class":59},"   \"",[49,651,652],{"class":489},"120",[49,654,486],{"class":59},[49,656,73],{"class":59},[49,658,585],{"class":59},[49,660,661],{"class":489},"$155,880",[49,663,486],{"class":59},[49,665,611],{"class":59},[49,667,669,671,673,676,678,680,682,685,687,689,692,695,697,699,701,704,706],{"class":51,"line":668},32,[49,670,628],{"class":59},[49,672,486],{"class":59},[49,674,675],{"class":489},"Wireless Mouse",[49,677,486],{"class":59},[49,679,73],{"class":59},[49,681,585],{"class":59},[49,683,684],{"class":489},"EU",[49,686,486],{"class":59},[49,688,73],{"class":59},[49,690,691],{"class":59},"  \"",[49,693,694],{"class":489},"640",[49,696,486],{"class":59},[49,698,73],{"class":59},[49,700,585],{"class":59},[49,702,703],{"class":489},"$19,193",[49,705,486],{"class":59},[49,707,611],{"class":59},[49,709,711,713,715,718,720,722,725,728,730,732,734,737,739,741,743,746,748],{"class":51,"line":710},33,[49,712,628],{"class":59},[49,714,486],{"class":59},[49,716,717],{"class":489},"USB-C Hub",[49,719,486],{"class":59},[49,721,73],{"class":59},[49,723,724],{"class":59},"      \"",[49,726,727],{"class":489},"APAC",[49,729,486],{"class":59},[49,731,73],{"class":59},[49,733,486],{"class":59},[49,735,736],{"class":489},"410",[49,738,486],{"class":59},[49,740,73],{"class":59},[49,742,585],{"class":59},[49,744,745],{"class":489},"$20,495",[49,747,486],{"class":59},[49,749,611],{"class":59},[49,751,753,755,757,760,763,765,767,769,771,773,775,777,780,782,784,786,789,791],{"class":51,"line":752},34,[49,754,628],{"class":59},[49,756,486],{"class":59},[49,758,759],{"class":489},"Monitor 27",[49,761,762],{"class":55},"\\\"",[49,764,486],{"class":59},[49,766,73],{"class":59},[49,768,649],{"class":59},[49,770,642],{"class":489},[49,772,486],{"class":59},[49,774,73],{"class":59},[49,776,691],{"class":59},[49,778,779],{"class":489},"180",[49,781,486],{"class":59},[49,783,73],{"class":59},[49,785,585],{"class":59},[49,787,788],{"class":489},"$71,820",[49,790,486],{"class":59},[49,792,611],{"class":59},[49,794,796,798,800,803,805,807,810,812,814,816,818,821,823,825,827,830,832],{"class":51,"line":795},35,[49,797,628],{"class":59},[49,799,486],{"class":59},[49,801,802],{"class":489},"Keyboard",[49,804,486],{"class":59},[49,806,73],{"class":59},[49,808,809],{"class":59},"       \"",[49,811,684],{"class":489},[49,813,486],{"class":59},[49,815,73],{"class":59},[49,817,691],{"class":59},[49,819,820],{"class":489},"320",[49,822,486],{"class":59},[49,824,73],{"class":59},[49,826,585],{"class":59},[49,828,829],{"class":489},"$25,596",[49,831,486],{"class":59},[49,833,611],{"class":59},[49,835,837,839,841,844,846,848,850,852,854,856,858,861,863,865,867,870,872],{"class":51,"line":836},36,[49,838,628],{"class":59},[49,840,486],{"class":59},[49,842,843],{"class":489},"Webcam HD",[49,845,486],{"class":59},[49,847,73],{"class":59},[49,849,724],{"class":59},[49,851,727],{"class":489},[49,853,486],{"class":59},[49,855,73],{"class":59},[49,857,486],{"class":59},[49,859,860],{"class":489},"260",[49,862,486],{"class":59},[49,864,73],{"class":59},[49,866,585],{"class":59},[49,868,869],{"class":489},"$23,397",[49,871,486],{"class":59},[49,873,611],{"class":59},[49,875,877],{"class":51,"line":876},37,[49,878,879],{"class":59},"                },\n",[49,881,883,886,888,891,893,896,898,901,903,906,908,911],{"class":51,"line":882},38,[49,884,885],{"class":55},"                template",[49,887,60],{"class":59},[49,889,890],{"class":63},"ColumnWidths",[49,892,67],{"class":59},[49,894,895],{"class":101},"40",[49,897,73],{"class":59},[49,899,900],{"class":101}," 20",[49,902,73],{"class":59},[49,904,905],{"class":101}," 15",[49,907,73],{"class":59},[49,909,910],{"class":101}," 25",[49,912,279],{"class":59},[49,914,916,918,920,923],{"class":51,"line":915},39,[49,917,885],{"class":55},[49,919,60],{"class":59},[49,921,922],{"class":63},"TableHeaderStyle",[49,924,256],{"class":59},[49,926,928,931,933,936,938,940,942,945],{"class":51,"line":927},40,[49,929,930],{"class":55},"                    template",[49,932,60],{"class":59},[49,934,935],{"class":63},"TextColor",[49,937,67],{"class":59},[49,939,91],{"class":55},[49,941,60],{"class":59},[49,943,944],{"class":55},"White",[49,946,279],{"class":59},[49,948,950,952,954,957,959,962],{"class":51,"line":949},41,[49,951,930],{"class":55},[49,953,60],{"class":59},[49,955,956],{"class":63},"BgColor",[49,958,67],{"class":59},[49,960,961],{"class":55},"brand",[49,963,279],{"class":59},[49,965,967],{"class":51,"line":966},42,[49,968,969],{"class":59},"                ),\n",[49,971,973,975,977,979,981,984],{"class":51,"line":972},43,[49,974,885],{"class":55},[49,976,60],{"class":59},[49,978,86],{"class":63},[49,980,67],{"class":59},[49,982,983],{"class":55},"stripe",[49,985,279],{"class":59},[49,987,989],{"class":51,"line":988},44,[49,990,991],{"class":59},"            )\n",[49,993,995],{"class":51,"line":994},45,[49,996,997],{"class":59},"        })\n",[49,999,1001],{"class":51,"line":1000},46,[49,1002,1003],{"class":59},"    })\n",[49,1005,1007],{"class":51,"line":1006},47,[49,1008,133],{"emptyLinePlaceholder":132},[49,1010,1012,1015,1017,1020,1022,1024,1026,1029],{"class":51,"line":1011},48,[49,1013,1014],{"class":55},"    data",[49,1016,73],{"class":59},[49,1018,1019],{"class":55}," err ",[49,1021,245],{"class":59},[49,1023,393],{"class":55},[49,1025,60],{"class":59},[49,1027,1028],{"class":63},"Generate",[49,1030,401],{"class":59},[49,1032,1034,1037,1039,1042,1045],{"class":51,"line":1033},49,[49,1035,1036],{"class":139},"    if",[49,1038,1019],{"class":55},[49,1040,1041],{"class":59},"!=",[49,1043,1044],{"class":59}," nil",[49,1046,236],{"class":59},[49,1048,1050,1053,1055,1058,1060,1063],{"class":51,"line":1049},50,[49,1051,1052],{"class":55},"        log",[49,1054,60],{"class":59},[49,1056,1057],{"class":63},"Fatal",[49,1059,67],{"class":59},[49,1061,1062],{"class":55},"err",[49,1064,216],{"class":59},[49,1066,1068],{"class":51,"line":1067},51,[49,1069,1070],{"class":59},"    }\n",[49,1072,1074,1076,1078,1080,1083,1085,1088,1090,1092,1095,1097,1099,1102,1104,1107,1110,1112,1114,1116],{"class":51,"line":1073},52,[49,1075,1036],{"class":139},[49,1077,1019],{"class":55},[49,1079,245],{"class":59},[49,1081,1082],{"class":55}," os",[49,1084,60],{"class":59},[49,1086,1087],{"class":63},"WriteFile",[49,1089,67],{"class":59},[49,1091,486],{"class":59},[49,1093,1094],{"class":489},"sales.pdf",[49,1096,486],{"class":59},[49,1098,73],{"class":59},[49,1100,1101],{"class":55}," data",[49,1103,73],{"class":59},[49,1105,1106],{"class":101}," 0o644",[49,1108,1109],{"class":59},");",[49,1111,1019],{"class":55},[49,1113,1041],{"class":59},[49,1115,1044],{"class":59},[49,1117,236],{"class":59},[49,1119,1121,1123,1125,1127,1129,1131],{"class":51,"line":1120},53,[49,1122,1052],{"class":55},[49,1124,60],{"class":59},[49,1126,1057],{"class":63},[49,1128,67],{"class":59},[49,1130,1062],{"class":55},[49,1132,216],{"class":59},[49,1134,1136],{"class":51,"line":1135},54,[49,1137,1070],{"class":59},[49,1139,1141],{"class":51,"line":1140},55,[49,1142,1143],{"class":59},"}\n",[19,1145,1146,1149],{},[23,1147,1148],{},"go run main.go",". Six body rows, three of them tinted, header in dark blue with white text. The kind of report that goes in a Monday email.",[14,1151,1153],{"id":1152},"how-the-alternation-works","How the alternation works",[19,1155,1156,1157,1160,1161,1164],{},"Internally, gpdf walks the body rows with an index ",[23,1158,1159],{},"i"," starting at 0 and applies the stripe to rows where ",[23,1162,1163],{},"i%2 == 1",". The header row is its own slice and isn't counted. So:",[1166,1167,1168,1184],"table",{},[1169,1170,1171],"thead",{},[1172,1173,1174,1178,1181],"tr",{},[1175,1176,1177],"th",{},"Body row index (0-based)",[1175,1179,1180],{},"Visually",[1175,1182,1183],{},"Striped?",[1185,1186,1187,1199,1213,1223,1235],"tbody",{},[1172,1188,1189,1193,1196],{},[1190,1191,1192],"td",{},"0",[1190,1194,1195],{},"1st",[1190,1197,1198],{},"no",[1172,1200,1201,1204,1207],{},[1190,1202,1203],{},"1",[1190,1205,1206],{},"2nd",[1190,1208,1209],{},[1210,1211,1212],"strong",{},"yes",[1172,1214,1215,1218,1221],{},[1190,1216,1217],{},"2",[1190,1219,1220],{},"3rd",[1190,1222,1198],{},[1172,1224,1225,1228,1231],{},[1190,1226,1227],{},"3",[1190,1229,1230],{},"4th",[1190,1232,1233],{},[1210,1234,1212],{},[1172,1236,1237,1240,1242],{},[1190,1238,1239],{},"...",[1190,1241,1239],{},[1190,1243,1239],{},[19,1245,1246],{},"That parity matches the Bootstrap convention. The first row of data sits clean, and the stripe is the visual \"rest\" — your eye travels across the white row, the next is shaded, repeat.",[19,1248,1249],{},"There's no option to flip the parity (stripe odd-indexed rows instead). If you really want it inverted, prepend an empty row to the body — but you don't, because nobody actually wants that.",[14,1251,1253],{"id":1252},"pick-the-color","Pick the color",[19,1255,1256,1257,1260],{},"The whole point is ",[1210,1258,1259],{},"subtle",". A stripe loud enough to compete with the text defeats itself.",[40,1262,1264],{"className":42,"code":1263,"language":44,"meta":45,"style":45},"pdf.RGBHex(0xF5F5F5) // gentle warm gray — Bootstrap default territory\npdf.RGBHex(0xFAFAFA) // even softer, almost imperceptible at small sizes\npdf.RGBHex(0xEEF2FF) // pale brand tint (works if header is the brand color)\npdf.Gray(0.96)       // grayscale equivalent — saves a few bytes in PDF/A workflows\n",[23,1265,1266,1283,1301,1319],{"__ignoreMap":45},[49,1267,1268,1270,1272,1274,1276,1278,1280],{"class":51,"line":52},[49,1269,91],{"class":55},[49,1271,60],{"class":59},[49,1273,96],{"class":63},[49,1275,67],{"class":59},[49,1277,102],{"class":101},[49,1279,350],{"class":59},[49,1281,1282],{"class":353}," // gentle warm gray — Bootstrap default territory\n",[49,1284,1285,1287,1289,1291,1293,1296,1298],{"class":51,"line":129},[49,1286,91],{"class":55},[49,1288,60],{"class":59},[49,1290,96],{"class":63},[49,1292,67],{"class":59},[49,1294,1295],{"class":101},"0xFAFAFA",[49,1297,350],{"class":59},[49,1299,1300],{"class":353}," // even softer, almost imperceptible at small sizes\n",[49,1302,1303,1305,1307,1309,1311,1314,1316],{"class":51,"line":136},[49,1304,91],{"class":55},[49,1306,60],{"class":59},[49,1308,96],{"class":63},[49,1310,67],{"class":59},[49,1312,1313],{"class":101},"0xEEF2FF",[49,1315,350],{"class":59},[49,1317,1318],{"class":353}," // pale brand tint (works if header is the brand color)\n",[49,1320,1321,1323,1325,1328,1330,1333,1335],{"class":51,"line":146},[49,1322,91],{"class":55},[49,1324,60],{"class":59},[49,1326,1327],{"class":63},"Gray",[49,1329,67],{"class":59},[49,1331,1332],{"class":101},"0.96",[49,1334,350],{"class":59},[49,1336,1337],{"class":353},"       // grayscale equivalent — saves a few bytes in PDF/A workflows\n",[19,1339,1340],{},"Avoid saturated colors. A blue stripe at 60% saturation reads \"this row is selected/important\" and breaks the across-row scan that zebra striping is supposed to fix.",[19,1342,1343,1344,1347,1348,1351],{},"For dark themes (rare in PDFs but they exist for slide-style reports), ",[23,1345,1346],{},"pdf.RGBHex(0x202020)"," over a ",[23,1349,1350],{},"0x1A1A1A"," page works. Keep the contrast ratio low.",[14,1353,1355],{"id":1354},"combine-with-cell-borders","Combine with cell borders",[19,1357,1358,1359,1362],{},"Stripes alone are enough for short tables. For dense, finance-style tables, pair stripes with ",[23,1360,1361],{},"WithTableCellBorder"," to draw a hairline between every cell:",[40,1364,1366],{"className":42,"code":1365,"language":44,"meta":45,"style":45},"hairline := template.Border(\n    template.BorderWidth(document.Pt(0.5)),\n    template.BorderColor(pdf.Gray(0.85)),\n)\n\nc.Table(header, rows,\n    template.ColumnWidths(40, 20, 15, 25),\n    template.TableHeaderStyle(\n        template.TextColor(pdf.White),\n        template.BgColor(brand),\n    ),\n    template.TableStripe(pdf.RGBHex(0xF5F5F5)),\n    template.WithTableCellBorder(hairline),\n)\n",[23,1367,1368,1384,1411,1435,1439,1443,1462,1488,1498,1517,1531,1536,1558,1573],{"__ignoreMap":45},[49,1369,1370,1373,1375,1377,1379,1382],{"class":51,"line":52},[49,1371,1372],{"class":55},"hairline ",[49,1374,245],{"class":59},[49,1376,81],{"class":55},[49,1378,60],{"class":59},[49,1380,1381],{"class":63},"Border",[49,1383,256],{"class":59},[49,1385,1386,1389,1391,1394,1396,1398,1400,1403,1405,1408],{"class":51,"line":129},[49,1387,1388],{"class":55},"    template",[49,1390,60],{"class":59},[49,1392,1393],{"class":63},"BorderWidth",[49,1395,67],{"class":59},[49,1397,294],{"class":55},[49,1399,60],{"class":59},[49,1401,1402],{"class":63},"Pt",[49,1404,67],{"class":59},[49,1406,1407],{"class":101},"0.5",[49,1409,1410],{"class":59},")),\n",[49,1412,1413,1415,1417,1420,1422,1424,1426,1428,1430,1433],{"class":51,"line":136},[49,1414,1388],{"class":55},[49,1416,60],{"class":59},[49,1418,1419],{"class":63},"BorderColor",[49,1421,67],{"class":59},[49,1423,91],{"class":55},[49,1425,60],{"class":59},[49,1427,1327],{"class":63},[49,1429,67],{"class":59},[49,1431,1432],{"class":101},"0.85",[49,1434,1410],{"class":59},[49,1436,1437],{"class":51,"line":146},[49,1438,216],{"class":59},[49,1440,1441],{"class":51,"line":158},[49,1442,133],{"emptyLinePlaceholder":132},[49,1444,1445,1447,1449,1451,1453,1455,1457,1459],{"class":51,"line":168},[49,1446,56],{"class":55},[49,1448,60],{"class":59},[49,1450,64],{"class":63},[49,1452,67],{"class":59},[49,1454,70],{"class":55},[49,1456,73],{"class":59},[49,1458,76],{"class":55},[49,1460,1461],{"class":59},",\n",[49,1463,1464,1466,1468,1470,1472,1474,1476,1478,1480,1482,1484,1486],{"class":51,"line":173},[49,1465,1388],{"class":55},[49,1467,60],{"class":59},[49,1469,890],{"class":63},[49,1471,67],{"class":59},[49,1473,895],{"class":101},[49,1475,73],{"class":59},[49,1477,900],{"class":101},[49,1479,73],{"class":59},[49,1481,905],{"class":101},[49,1483,73],{"class":59},[49,1485,910],{"class":101},[49,1487,279],{"class":59},[49,1489,1490,1492,1494,1496],{"class":51,"line":183},[49,1491,1388],{"class":55},[49,1493,60],{"class":59},[49,1495,922],{"class":63},[49,1497,256],{"class":59},[49,1499,1500,1503,1505,1507,1509,1511,1513,1515],{"class":51,"line":193},[49,1501,1502],{"class":55},"        template",[49,1504,60],{"class":59},[49,1506,935],{"class":63},[49,1508,67],{"class":59},[49,1510,91],{"class":55},[49,1512,60],{"class":59},[49,1514,944],{"class":55},[49,1516,279],{"class":59},[49,1518,1519,1521,1523,1525,1527,1529],{"class":51,"line":203},[49,1520,1502],{"class":55},[49,1522,60],{"class":59},[49,1524,956],{"class":63},[49,1526,67],{"class":59},[49,1528,961],{"class":55},[49,1530,279],{"class":59},[49,1532,1533],{"class":51,"line":213},[49,1534,1535],{"class":59},"    ),\n",[49,1537,1538,1540,1542,1544,1546,1548,1550,1552,1554,1556],{"class":51,"line":219},[49,1539,1388],{"class":55},[49,1541,60],{"class":59},[49,1543,86],{"class":63},[49,1545,67],{"class":59},[49,1547,91],{"class":55},[49,1549,60],{"class":59},[49,1551,96],{"class":63},[49,1553,67],{"class":59},[49,1555,102],{"class":101},[49,1557,1410],{"class":59},[49,1559,1560,1562,1564,1566,1568,1571],{"class":51,"line":224},[49,1561,1388],{"class":55},[49,1563,60],{"class":59},[49,1565,1361],{"class":63},[49,1567,67],{"class":59},[49,1569,1570],{"class":55},"hairline",[49,1572,279],{"class":59},[49,1574,1575],{"class":51,"line":239},[49,1576,216],{"class":59},[19,1578,1579],{},"Hairline borders + light stripe = the look of every accountant's spreadsheet print preview, deliberately. Keep the border lighter than the stripe so the stripe stays the dominant signal.",[19,1581,1582,1583,1585,1586,60],{},"If you only want an outer frame (no inner grid), swap ",[23,1584,1361],{}," for ",[23,1587,1588],{},"WithTableBorder",[14,1590,1592],{"id":1591},"mistakes-that-cost-ten-minutes","Mistakes that cost ten minutes",[1594,1595,1596,1611,1623,1640],"ul",{},[1597,1598,1599,1602,1603,1606,1607,1610],"li",{},[1210,1600,1601],{},"Color in the wrong unit range."," ",[23,1604,1605],{},"pdf.RGB(245, 245, 245)"," produces a black box. The constructor expects 0.0–1.0, not 0–255. Use ",[23,1608,1609],{},"pdf.RGBHex(0xF5F5F5)"," if you're thinking in CSS values.",[1597,1612,1613,1602,1616,1618,1619,1622],{},[1210,1614,1615],{},"Striping the header.",[23,1617,86],{}," does not touch the header. If you want a tinted header, that's ",[23,1620,1621],{},"TableHeaderStyle(template.BgColor(...))"," — a different option. Confusing the two and then wondering why the header isn't tinted is the classic first-time bug.",[1597,1624,1625,1628,1629,1632,1633,1635,1636,1639],{},[1210,1626,1627],{},"Two-color alternation."," gpdf supports one stripe color, not two. If you set both ",[23,1630,1631],{},"pdf.White"," (row 0) and ",[23,1634,102],{}," (row 1), you don't actually need to set white — the page is already white. Asking for ",[23,1637,1638],{},"[white, gray, blue]"," 3-cycle is not a feature; it would also be hostile to the reader.",[1597,1641,1642,1645],{},[1210,1643,1644],{},"Stripes on a 3-row table."," A stripe needs at least 4–5 body rows to do its job. On 2–3 rows, it just looks like one cell got selected. Skip it; let the table breathe.",[14,1647,1649],{"id":1648},"related-recipes","Related recipes",[1594,1651,1652,1662,1669],{},[1597,1653,1654,1658,1659,1661],{},[28,1655,1657],{"href":1656},"/blog/table-column-widths","How do I set custom column widths for a table?"," — ",[23,1660,890],{}," in detail.",[1597,1663,1664,1668],{},[28,1665,1667],{"href":1666},"/blog/add-custom-truetype-font","How do I add a custom TrueType font to gpdf?"," — make the table render in your brand font.",[1597,1670,1671,1675],{},[28,1672,1674],{"href":1673},"/blog/invoice-pdf-go-under-50-lines","Generate an invoice PDF in Go in under 50 lines"," — a real-world table with header style, stripe, and totals.",[14,1677,1679],{"id":1678},"try-gpdf","Try gpdf",[19,1681,1682],{},"gpdf is a Go library for generating PDFs. MIT licensed, zero external dependencies, pure-Go TrueType handling.",[40,1684,1688],{"className":1685,"code":1686,"language":1687,"meta":45,"style":45},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com/gpdf-dev/gpdf\n","bash",[23,1689,1690],{"__ignoreMap":45},[49,1691,1692,1694,1697],{"class":51,"line":52},[49,1693,44],{"class":125},[49,1695,1696],{"class":489}," get",[49,1698,1699],{"class":489}," github.com/gpdf-dev/gpdf\n",[19,1701,1702,1706,1707],{},[28,1703,1705],{"href":30,"rel":1704},[32],"⭐ Star on GitHub"," · ",[28,1708,1711],{"href":1709,"rel":1710},"https://gpdf.dev/docs/quickstart",[32],"Read the docs",[1713,1714,1715],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":45,"searchDepth":129,"depth":129,"links":1717},[1718,1719,1720,1721,1722,1723,1724,1725,1726],{"id":16,"depth":129,"text":17},{"id":37,"depth":129,"text":38},{"id":111,"depth":129,"text":112},{"id":1152,"depth":129,"text":1153},{"id":1252,"depth":129,"text":1253},{"id":1354,"depth":129,"text":1355},{"id":1591,"depth":129,"text":1592},{"id":1648,"depth":129,"text":1649},{"id":1678,"depth":129,"text":1679},"2026-05-04","Pass template.TableStripe to a table call. gpdf paints the alternate body rows with the color you give it. No row-loop, no manual cell styling.",false,"md",{"name":1732,"totalTime":1733,"tools":1734,"steps":1736},"Add zebra-striped rows to a gpdf table","PT5M",[1735,178],"Go 1.22+",[1737,1740,1743],{"name":1738,"text":1739},"Pick a stripe color","Build a pdf.Color with pdf.RGBHex(0xF5F5F5) for a soft gray, or pdf.RGB(r, g, b) with values in 0.0–1.0. Anything readable behind body text works — keep it light.",{"name":1741,"text":1742},"Pass template.TableStripe to the Table call","Inside a column, call c.Table(header, rows, template.TableStripe(stripeColor)). gpdf walks the body rows and applies the color to every other one.",{"name":1744,"text":1745},"Pair it with TableHeaderStyle for contrast","Add template.TableHeaderStyle(template.TextColor(pdf.White), template.BgColor(brand)) so the header sits visually separate from the striped body. Stripes work but feel half-finished without a styled header.",null,{},"/blog/zebra-striped-table-rows",{"title":5,"description":1728},"blog/019.zebra-striped-table-rows",[1752,1753,1754],"recipe","tutorial","templates","GyhMZhHkOb4zcruYd1xI34nFFChKzqGoeJfT4ZOFIf8",1779199010179]