Area Listeners
Area listeners let you intercept every cell transformation — before and after — without writing a custom command. Use them for conditional row styling, audit logging, data validation, or any cross-cutting concern.
The AreaListener interface
Section titled “The AreaListener interface”type AreaListener interface { BeforeTransformCell(src, target CellRef, ctx *Context, tx Transformer) bool AfterTransformCell(src, target CellRef, ctx *Context, tx Transformer)}BeforeTransformCell— called before each cell is processed. Returnfalseto skip the default transformation (you handle it yourself). Returntrueto proceed normally.AfterTransformCell— called after each cell is processed. Use it for post-processing like styling.
Both receive the source cell (template position), target cell (output position), the data context, and the transformer.
Registering a listener
Section titled “Registering a listener”xlfill.Fill("template.xlsx", "output.xlsx", data, xlfill.WithAreaListener(&MyListener{}),)Example: Alternate row colors
Section titled “Example: Alternate row colors”type AlternateRowListener struct{}
func (l *AlternateRowListener) BeforeTransformCell( src, target xlfill.CellRef, ctx *xlfill.Context, tx xlfill.Transformer,) bool { return true // proceed with default transformation}
func (l *AlternateRowListener) AfterTransformCell( src, target xlfill.CellRef, ctx *xlfill.Context, tx xlfill.Transformer,) { if target.Row%2 == 0 { // Use transformer API to apply a light background }}Example: Audit logging
Section titled “Example: Audit logging”type AuditListener struct{}
func (l *AuditListener) BeforeTransformCell( src, target xlfill.CellRef, ctx *xlfill.Context, tx xlfill.Transformer,) bool { log.Printf("Processing cell %s -> %s", src, target) return true}
func (l *AuditListener) AfterTransformCell( src, target xlfill.CellRef, ctx *xlfill.Context, tx xlfill.Transformer,) {}StyleListener: conditional styling
Section titled “StyleListener: conditional styling”For conditional formatting based on cell values, implement StyleListener. It’s called after each cell is transformed and lets you override style properties:
type StyleListener interface { StyleCell(target CellRef, value any, ctx *Context) *StyleOverride}
type StyleOverride struct { Bold *bool Italic *bool FontColor *string // hex color e.g. "#FF0000" FillColor *string // hex background color FontSize *float64}Example: Red text for negative values
Section titled “Example: Red text for negative values”type NegativeHighlighter struct{}
func (l *NegativeHighlighter) BeforeTransformCell( src, target xlfill.CellRef, ctx *xlfill.Context, tx xlfill.Transformer,) bool { return true }
func (l *NegativeHighlighter) AfterTransformCell( src, target xlfill.CellRef, ctx *xlfill.Context, tx xlfill.Transformer,) {}
func (l *NegativeHighlighter) StyleCell( target xlfill.CellRef, value any, ctx *xlfill.Context,) *xlfill.StyleOverride { if f, ok := value.(float64); ok && f < 0 { color := "FF0000" bold := true return &xlfill.StyleOverride{FontColor: &color, Bold: &bold} } return nil // no change}Register it the same way as any listener:
xlfill.Fill("template.xlsx", "output.xlsx", data, xlfill.WithAreaListener(&NegativeHighlighter{}),)A listener can implement both AreaListener and StyleListener — the two are independent call paths.
Thread safety note: When used with WithParallelism, listeners are called from multiple goroutines. Use atomic operations or mutexes for any shared mutable state (counters, accumulators, etc.).
PreWrite callback
Section titled “PreWrite callback”For logic that runs after all template processing but before writing the output, use WithPreWrite:
xlfill.Fill("template.xlsx", "output.xlsx", data, xlfill.WithPreWrite(func(tx xlfill.Transformer) error { // Set print area, add final calculations, etc. return nil }),)Template sheet control
Section titled “Template sheet control”Related options for controlling the output:
// Keep the template sheet in output (default: removed)xlfill.WithKeepTemplateSheet(true)
// Hide the template sheet instead of removingxlfill.WithHideTemplateSheet(true)
// Don't clear unexpanded ${...} expressions (default: cleared)xlfill.WithClearTemplateCells(false)What’s next?
Section titled “What’s next?”Area listeners are one of several debugging tools. For the complete toolkit — including Validate(), Describe(), and common troubleshooting tips:
For the complete list of functions, options, and types: