Skip to content

Styling Guide

ABCrimson edited this page Mar 2, 2026 · 1 revision

Styling Guide

modern-xlsx uses a fluent StyleBuilder API to create cell styles. Each build() call returns a style index that can be assigned to any number of cells.

Creating a Style

const idx = wb.createStyle()
  .font({ bold: true })
  .build(wb.styles);

ws.cell('A1').styleIndex = idx;

Font

.font({
  name: 'Arial',        // font family
  size: 12,             // point size
  bold: true,           // bold weight
  italic: true,         // italic style
  underline: true,      // underline
  strike: true,         // strikethrough
  color: 'FF0000',      // hex color (no #)
})

Fill

.fill({
  pattern: 'solid',     // 'solid' | 'gray125' | 'none' | ...
  fgColor: 'FFFF00',    // foreground hex color
  bgColor: null,        // background hex color (optional)
})

Pattern types: none, solid, gray125, darkGray, mediumGray, lightGray, darkHorizontal, darkVertical, darkDown, darkUp, darkGrid, darkTrellis, lightHorizontal, lightVertical, lightDown, lightUp, lightGrid, lightTrellis

Border

.border({
  top:    { style: 'thin',   color: '000000' },
  bottom: { style: 'double', color: '000000' },
  left:   { style: 'medium', color: '000000' },
  right:  { style: 'thin',   color: '000000' },
})

Border styles: thin, medium, thick, double, dotted, dashed, dashDot, dashDotDot, mediumDashed, mediumDashDot, mediumDashDotDot, slantDashDot, hair

Alignment

.alignment({
  horizontal: 'center',  // 'left' | 'center' | 'right' | 'fill' | 'justify'
  vertical: 'top',       // 'top' | 'center' | 'bottom'
  wrapText: true,        // wrap long text
  textRotation: 45,      // degrees (0-180)
  indent: 2,             // indent level
  shrinkToFit: true,     // shrink text to fit cell
})

Number Format

.numberFormat('#,##0.00')    // custom format code
.numberFormat('$#,##0.00')   // currency
.numberFormat('0.00%')       // percentage
.numberFormat('yyyy-mm-dd')  // date

Common format codes:

Code Example Output
0 1234
0.00 1234.56
#,##0 1,235
#,##0.00 1,234.56
$#,##0.00 $1,234.56
0% 12%
0.00% 12.34%
yyyy-mm-dd 2024-01-15
mm/dd/yyyy 01/15/2024
h:mm AM/PM 2:30 PM
0.00E+00 1.23E+03

Protection

.protection({
  locked: true,    // prevent editing when sheet is protected
  hidden: false,   // hide formula in formula bar
})

Combining Styles

Chain multiple style methods:

const fancy = wb.createStyle()
  .font({ bold: true, size: 14, color: 'FFFFFF' })
  .fill({ pattern: 'solid', fgColor: '1F4E79' })
  .border({
    top:    { style: 'medium', color: '1F4E79' },
    bottom: { style: 'medium', color: '1F4E79' },
  })
  .alignment({ horizontal: 'center', vertical: 'center' })
  .numberFormat('#,##0.00')
  .build(wb.styles);

Reusing Styles

The build() return value is just a number (style index). Assign it to as many cells as needed:

const bold = wb.createStyle().font({ bold: true }).build(wb.styles);

ws.cell('A1').styleIndex = bold;
ws.cell('B1').styleIndex = bold;
ws.cell('C1').styleIndex = bold;

Reading Styles

When reading an existing workbook, cells have styleIndex values that reference entries in wb.styles.cellXfs. You can inspect the full style data:

const wb = await readFile('styled.xlsx');
const ws = wb.getSheet('Sheet1')!;
const cell = ws.cell('A1');

if (cell.styleIndex !== null) {
  const xf = wb.styles.cellXfs[cell.styleIndex];
  const font = wb.styles.fonts[xf.fontId];
  console.log(font.bold);  // true/false
}

Clone this wiki locally