You are reading the documentation of sheetsmith 1.0.x.See the latest version (1.0.x)
@ExcelSheet
Marks a class as a sheet class and configures its sheet: title, preset, shared style sheets, layout options and the header and body slots.
- Mandatory on every class passed to
SheetData. A class without it violates rule V-01. - Not inherited. Every exported class carries its own
@ExcelSheet. Superclasses that only contribute columns do not need it. - Every attribute is optional. With all defaults, the sheet has no title, a frozen header, auto-sized columns, no auto-filter, no frame, and no style other than the application default preset (which is
NONEunless configured).
Summary of the attributes:
| Attribute | Type | Default |
|---|---|---|
title |
String |
"" (no title) |
titleStyle |
String |
"" (no style) |
preset |
TablePreset |
INHERIT (application default) |
accentColor |
String |
"" (application default) |
styleSheets |
Class<?>[] |
{} |
freezeHeader |
boolean |
true |
autoFilter |
boolean |
false |
autoSizeColumns |
boolean |
true |
outerBorder |
Border |
INHERIT (no frame) |
outerBorderColor |
String |
"" (automatic colour) |
header |
HeaderStyles |
@HeaderStyles (no slot set) |
body |
BodyStyles |
@BodyStyles (no slot set) |
| Type | String |
| Default | "", meaning no title row |
| Allowed values | any text; written as it is |
| Effect | Adds a row above the header. The text is written in the first column and the cell is merged across all the columns of the table. Every cell of the title row receives the title style. |
| Interactions | The title has no role: header and body slots never apply to it. It is outside the outer frame. It is frozen together with the header when freezeHeader is true. It is excluded from the auto-filter. Its style is the preset title layer (if any) followed by titleStyle. With one column, there is nothing to merge: the title stays in the single cell. |
| Validation | None on the text itself. titleStyle requires a title (V-15). |
@ExcelSheet(title = "Open invoices at 30/09/2026")public record InvoiceRow(/* columns */) { }titleStyle
Section titled “titleStyle”| Type | String, the name of a named style |
| Default | "", meaning no style |
| Allowed values | the name of a style available to the class: declared on the class or on one of its styleSheets |
| Effect | Applied to every cell of the title row, after the preset title layer. |
| Interactions | Allowed only when title is set. |
| Validation | V-15 when title is empty; V-06 when the name does not exist. |
@ExcelSheet(title = "Quarterly sales", titleStyle = "title")@ExcelStyle(name = "title", fontSize = 16, bold = Toggle.TRUE, fontColor = "#1F4E79")public record SalesRow(/* columns */) { }preset
Section titled “preset”| Type | TablePreset |
| Default | TablePreset.INHERIT |
| Allowed values | INHERIT, NONE, LIGHT, MEDIUM, DARK |
| Effect | INHERIT uses the application default preset (SheetsmithDefaults.preset, property sheetsmith.preset, NONE unless configured). NONE applies no preset regardless of the application default. LIGHT, MEDIUM and DARK apply the corresponding preset. |
| Interactions | The preset is the lowest level of the title, header and body cascades: every declared style overrides it attribute by attribute. The colours of the preset come from the effective accent colour. |
| Validation | None. |
@ExcelSheet(preset = TablePreset.LIGHT) // always LIGHT@ExcelSheet(preset = TablePreset.NONE) // never a preset, even if the application default is one@ExcelSheet // the application default presetaccentColor
Section titled “accentColor”| Type | String, a colour |
| Default | "", meaning the application default accent colour (#4472C4 unless configured) |
| Allowed values | #RRGGBB in upper or lower case, or the name of an Apache POI IndexedColors constant (see section 6.2) |
| Effect | The colour from which the preset derives every tone. Hexadecimal values are normalised to upper case. |
| Interactions | Has an effect only when the effective preset is not NONE. |
| Validation | V-13 for any other non-empty value. |
@ExcelSheet(preset = TablePreset.MEDIUM, accentColor = "#2E7D32")styleSheets
Section titled “styleSheets”| Type | Class<?>[] |
| Default | {} |
| Allowed values | classes annotated with @ExcelStyleSheet |
| Effect | The named styles of the listed style sheets become available to the slots of this class, as if declared on it. |
| Interactions | A style declared on the sheet class with the same name as a style of a style sheet replaces it entirely (no merge). Listing the same style sheet twice has no effect. The order of the list has no effect. |
| Validation | V-09 for a listed class without @ExcelStyleSheet (its styles are then ignored, so references to them also report V-06). V-08 when two listed style sheets declare the same name. |
@ExcelSheet(styleSheets = {CorporateStyles.class, FinanceStyles.class}, header = @HeaderStyles(base = "corporate-header"))Section 8 is dedicated to shared style sheets.
freezeHeader
Section titled “freezeHeader”| Type | boolean |
| Default | true |
| Effect | Freezes the rows up to and including the header, so they stay visible while scrolling. When the sheet has a title, the title row is frozen too. No column is frozen. |
| Validation | None. |
@ExcelSheet(freezeHeader = false)autoFilter
Section titled “autoFilter”| Type | boolean |
| Default | false |
| Effect | Adds an Excel auto-filter covering all the columns, from the header row to the last data row. With no data rows, it covers the header row only. The title is never included. |
| Validation | None. |
@ExcelSheet(autoFilter = true)autoSizeColumns
Section titled “autoSizeColumns”| Type | boolean |
| Default | true |
| Effect | Sizes every column without an explicit width to its content. |
| Interactions | Columns with @ExcelColumn.width are never auto-sized. When false, columns without width keep the width chosen by the spreadsheet application. |
| Validation | None. |
How sizing works:
- Sizing is delegated to Apache POI, which measures the text with the fonts installed on the machine (Java AWT).
- On servers or containers without installed fonts, or without the AWT native libraries, that measurement can fail. sheetsmith then falls back to an estimate: the length in characters of the longest value of the column as Excel displays it (with its format applied, so dates and numbers are measured as shown), header included and title excluded, plus 2 characters, capped at 255.
- The time spent sizing grows with the number of rows. For large sheets, disable it and set explicit widths: see section 12.3.
A known behaviour concerns a sheet with a title and a single column: see section 12.4.
@ExcelSheet(autoSizeColumns = false)public record LargeRow( @ExcelColumn(header = "Id", order = 10, width = 10) long id, @ExcelColumn(header = "Description", order = 20, width = 60) String description) { }outerBorder
Section titled “outerBorder”| Type | Border |
| Default | Border.INHERIT, meaning no frame |
| Allowed values | every Border constant (see Appendix B) |
| Effect | Draws a frame around the header and the data rows with a single attribute: along the top of the header row, the left side of the first column, the right side of the last column, and the bottom of the last data row (or of the header row when there are no data rows). The title is never framed. |
| Interactions | Any value other than INHERIT, NONE included, is applied to those edges: NONE therefore removes, on the edges, borders that a preset or a base style would draw. In the cascade, the frame sits above the preset, the base slots and the odd and even slots, and below the first and last row and column slots, the column slots and the column header style: a style at those levels that sets a border side overrides the frame on that side. |
| Validation | None. |
Edges set by the frame, per cell:
| Cell | Sides set by the frame |
|---|---|
| Header, every column | top |
| Header, first column | left |
| Header, last column | right |
| Header, every column, only when there are no data rows | bottom |
| Data, first column | left |
| Data, last column | right |
| Data, last row | bottom |
@ExcelSheet(outerBorder = Border.MEDIUM, outerBorderColor = "#1F4E79")outerBorderColor
Section titled “outerBorderColor”| Type | String, a colour |
| Default | "", meaning the automatic colour (usually black) |
| Allowed values | #RRGGBB or an IndexedColors name |
| Effect | Colour of the frame edges. Hexadecimal values are normalised to upper case. |
| Interactions | Has an effect only when outerBorder is set. |
| Validation | V-13 for an invalid non-empty value. |
header
Section titled “header”| Type | HeaderStyles |
| Default | @HeaderStyles, no slot set |
| Effect | The named styles of the header row: see section 4.6. |
| Type | BodyStyles |
| Default | @BodyStyles, no slot set |
| Effect | The named styles of the data rows at table level: see section 4.7. |
Complete example
Section titled “Complete example”@ExcelSheet( title = "Invoice 2026/0042", titleStyle = "title", preset = TablePreset.LIGHT, accentColor = "#1F4E79", styleSheets = CorporateStyles.class, freezeHeader = true, autoFilter = true, autoSizeColumns = true, outerBorder = Border.THIN, outerBorderColor = "#1F4E79", header = @HeaderStyles(base = "header", lastColumn = "header-right"), body = @BodyStyles(lastRow = "total"))@ExcelStyle(name = "title", fontSize = 16, bold = Toggle.TRUE)@ExcelStyle(name = "header-right", align = Align.RIGHT)@ExcelStyle(name = "total", bold = Toggle.TRUE, borderTop = Border.DOUBLE)public record InvoiceLine( @ExcelColumn(header = "Description", order = 10) String description, @ExcelColumn(header = "Quantity", order = 20, format = "0") int quantity, @ExcelColumn(header = "Amount", order = 30, format = "#,##0.00") BigDecimal amount) {}In this example header is assumed to be declared on CorporateStyles.