Styles and Formats
CellStyle
CellStyle is an immutable value built through a builder, and applied to a cell,
a range, a row, or a column.
import io.keikai.axyra.sheets.style.*;
CellStyle header = CellStyle.builder()
.fontName("Calibri")
.fontSize(11)
.bold(true)
.fontColor(Color.rgb(0xFF, 0xFF, 0xFF))
.fill(Color.rgb(0x2C, 0x3E, 0x50))
.horizontalAlign(HAlign.CENTER)
.verticalAlign(VAlign.CENTER)
.wrapText(true)
.build();
sheet.range("A1:D1").setStyle(header);
Being immutable, a style is safely shared across cells and threads. To derive a
variant, use toBuilder():
CellStyle headerRight = header.toBuilder().horizontalAlign(HAlign.RIGHT).build();
Applying styles
cell.setStyle(style);
range.setStyle(style);
sheet.setRowStyle(0, style);
sheet.setColumnStyle(0, style);
Row and column styles are the defaults for cells that have none of their own, and are the cheap way to style a whole column without touching every cell.
Named styles
Register a style once on the workbook and apply it by name. Named styles are written to the file, so they appear in Excel’s style gallery:
wb.registerNamedStyle("Currency", currencyStyle);
sheet.range("C2:C100").applyNamedStyle("Currency");
wb.hasNamedStyle("Currency");
wb.updateNamedStyle("Currency", revised); // repaints every cell using it
wb.removeNamedStyle("Currency");
updateNamedStyle is the reason to prefer named styles for anything a user might
restyle later — one call changes every cell that references it.
Serializing a style
String json = style.toJson();
CellStyle restored = CellStyle.fromJson(json);
Useful for caching styles outside the workbook, or for shipping a style definition through your own configuration.
Colors
Five ways to specify a colour, and the distinction is not cosmetic:
Color.rgb(0xC0, 0x39, 0x2B); // literal RGB
Color.argb(0x80, 0xC0, 0x39, 0x2B);
Color.of(0xFFC0392B); // packed ARGB
Color.parse("#C0392B");
Color.indexed(10); // legacy indexed palette (.xls)
Color.theme(4); // a theme slot — follows the workbook theme
Color.theme(4, -0.25); // a theme slot, shaded 25% darker
Color.auto(); // "automatic" — resolved by the consumer
Prefer Color.theme(...) for anything that should follow the workbook’s theme.
An RGB literal is frozen; a theme colour changes when the theme does, which is
what a user expects when they switch a workbook’s theme.
Color.indexed(...) exists for legacy .xls fidelity. Do not use it in new
workbooks.
Fills
.fill(Color.parse("#2C3E50")) // solid
.fillPattern(PatternType.LIGHT_GRID, foreground, background) // patterned
.gradientFill(90, Color.parse("#FFFFFF"), Color.parse("#4A90D9"))
.pathGradientFill(Color.parse("#FFFFFF"), Color.parse("#4A90D9"))
PatternType covers Excel’s eighteen fill patterns; SOLID with fill(...) is
the common case.
Borders
Borders are per-edge. Side is LEFT, RIGHT, TOP, BOTTOM, or DIAGONAL:
CellStyle boxed = CellStyle.builder()
.border(Side.TOP, BorderStyle.THIN, Color.parse("#333333"))
.border(Side.BOTTOM, BorderStyle.DOUBLE, Color.parse("#333333"))
.build();
CellStyle grid = CellStyle.builder()
.allBorders(BorderStyle.THIN, Color.parse("#CCCCCC"))
.build();
BorderStyle runs from HAIR through THIN, MEDIUM, THICK, DOUBLE, and
the dashed and dash-dot variants. A diagonal border also needs
diagonalUp(true) or diagonalDown(true) to say which way it runs.
The engine resolves conflicts between neighbouring cells the way a spreadsheet application does — the heavier style wins on a shared edge — so you do not need to set both sides of a boundary.
Themes
A theme supplies the colour slots and the major/minor fonts that theme-relative styles resolve against:
Theme theme = Theme.builder()
.majorFont("Georgia")
.minorFont("Calibri")
.color(Theme.Slot.ACCENT1, Color.parse("#2C3E50"))
.color(Theme.Slot.HYPERLINK, Color.parse("#0563C1"))
.build();
The slots are DARK1, LIGHT1, DARK2, LIGHT2, ACCENT1–ACCENT6,
HYPERLINK, and FOLLOWED_HYPERLINK — the same twelve Excel exposes.
Changing the theme repaints every theme-relative colour in the workbook, and leaves RGB literals alone.
Number formats
A cell’s value and its display are separate. The number format code maps one to the other, using Excel’s format-code syntax:
CellStyle money = CellStyle.builder()
.numberFormat("#,##0.00;[Red](#,##0.00)")
.build();
CellStyle date = CellStyle.builder().numberFormat("yyyy-mm-dd").build();
Cell.formattedText() returns the formatted string. Read the raw value through
the matching CellValue variant accessor, such as CellValue.Number.value().
For dates, currencies, percentages, and anything with a conditional section,
these differ — which is the usual cause of “the number is wrong” reports that
turn out to be a format question.
Formatting outside a workbook
Formats applies a format code without needing a cell, which is handy for
rendering the same values in your own UI:
import io.keikai.axyra.sheets.format.Formats;
Formats.format(1234.5, "#,##0.00"); // "1,234.50"
Formats.format(1234.5, "#,##0.00", "de-DE"); // "1.234,50"
Parsing user input
Formats.parse applies the same coercion a spreadsheet does when a user types
into a cell — recognising numbers, dates, times, percentages, currencies, and
booleans, and reporting the format code it inferred:
ParsedValue pv = Formats.parse("31/12/2026");
Use it when you accept free-text input and want spreadsheet-compatible behaviour rather than your own parsing rules.
Next
- Cells and Ranges
- Content Objects — conditional formats apply styles based on cell values