From 8cdce5f1ef793b325bf869ae2acff667686dba7b Mon Sep 17 00:00:00 2001 From: Roland Boon Date: Fri, 2 Oct 2026 12:28:31 +0200 Subject: [PATCH] Add alignment to cell styles Allow setting text wrapping and vertical alignment for readable sheets with long form text. Serialize alignment as an xf child and preserve it when date formats are merged, so callers do not have to rewrite styles.xml. --- README.md | 4 ++++ test/index.js | 20 ++++++++++++++++++++ test/types.ts | 2 +- types/index.d.ts | 11 +++++++++++ xlsx.js | 8 +++++++- 5 files changed, 43 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8a85c30..d61b6dc 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,10 @@ const fileAsUint8Array = await createXlsx({ }) ``` +Styles accept an `alignment` object, for example +`{ alignment: { vertical: "center", wrapText: true } }`. +Alignment is preserved when a cell also uses a date or datetime format. + ## Contributing Follow [Coding Style Guide](https://github.com/litejs/litejs/wiki/Style-Guide), diff --git a/test/index.js b/test/index.js index 8ab460f..547dd28 100644 --- a/test/index.js +++ b/test/index.js @@ -4,6 +4,26 @@ describe("xlsx", function() { var { createFiles, createXlsx } = require("..") , compressionSuported = typeof CompressionStream !== "undefined" && typeof Response !== "undefined" + test("cell alignment and formatted styles", function(assert) { + var files = createFiles({ + styles: { + Wrapped: { font: { b: true }, alignment: { vertical: 'center', wrapText: true } }, + Unwrapped: { alignment: { horizontal: 'right', wrapText: false } } + }, + sheets: [[[ + { style: 'Wrapped', value: 'line one\nline two' }, + { style: 'Wrapped', format: 'date', value: new Date(1514900750001) }, + { style: 'Unwrapped', value: 10 } + ]]] + }) + , styles = files.find(f => f.name === 'xl/styles.xml').content + assert.equal((styles.match(//g) || []).length, 2, 'alignment survives format merging') + assert.ok(styles.includes('applyAlignment="1"'), 'alignment enabled on cell style') + assert.ok(styles.includes(''), 'false remains explicit') + assert.ok(!styles.includes('alignment="'), 'alignment is a child, never an attribute') + assert.end() + }) + function sheet1(data, sheet) { return createFiles({ sheets: [{ data, ...sheet }] }).find(f => f.name === 'xl/worksheets/sheet1.xml').content } diff --git a/test/types.ts b/test/types.ts index 613a4cf..e8767e4 100644 --- a/test/types.ts +++ b/test/types.ts @@ -2,7 +2,7 @@ import { createFiles, createXlsx, Workbook, XlsxFile } from ".." var workbook: Workbook = { styles: { - bold: { font: { sz: 11, name: "Calibri", b: true } }, + bold: { font: { sz: 11, name: "Calibri", b: true }, alignment: { vertical: "center", wrapText: true } }, border: { border: "thin" }, fill: { fill: "FFFF00" }, }, diff --git a/types/index.d.ts b/types/index.d.ts index 51d7069..614d031 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -36,7 +36,18 @@ export interface FillDef { pattern?: string } +export interface AlignmentDef { + horizontal?: "general" | "left" | "center" | "right" | "fill" | "justify" | "centerContinuous" | "distributed" + vertical?: "top" | "center" | "bottom" | "justify" | "distributed" + wrapText?: boolean + shrinkToFit?: boolean + textRotation?: number + indent?: number + readingOrder?: number +} + export interface StyleDef { + alignment?: AlignmentDef font?: FontDef border?: string | BorderSides fill?: string | FillDef diff --git a/xlsx.js b/xlsx.js index 05ddbe2..46bdef9 100644 --- a/xlsx.js +++ b/xlsx.js @@ -72,6 +72,8 @@ bgColor: normalizeRgb(newFill.bgColor) } a[1] = xf.push({ + alignment: a[1].alignment, + applyAlignment: a[1].alignment ? 1 : UNDEF, fontId: newFont ? font.push(newFont) - 1 : 0, applyFont: newFont ? 1 : UNDEF, borderId: newBorder ? border.push(newBorder) - 1 : UNDEF, @@ -190,7 +192,11 @@ (k, v) => toXml(k, { style: v && v.style || v }, v && v.color ? { color: [toColor(v.color)] } : 0) ) + '' + - toXml('cellXfs', { count: xf.length }, { xf }) + + toXml('cellXfs', { count: xf.length }, xf.map( + f => toXml('xf', assign({}, f, { alignment: UNDEF }), { + alignment: f.alignment ? [f.alignment] : UNDEF + }) + ).join('')) + '' + '' },