JavaScript (112)
Insert or Read Functions and Formulas in Excel Worksheets with JavaScript in React
2026-09-08 09:57:41 Written by jie zouIn Excel document processing, formulas and functions are among the most essential capabilities — whether summing, averaging, or performing date and trigonometric operations, formulas make data processing automated and efficient. Spire.XLS for JavaScript completes the insertion and reading of formulas and functions directly in the browser based on WebAssembly, and manages input and output files through a virtual file system (VFS), with no backend service required.
This article covers two core features:
- Insert Formulas and Functions into an Excel Worksheet
- Read Formulas and Functions from an Excel Worksheet
For installation and project configuration, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Insert Formulas and Functions into an Excel Worksheet
The Formula property of the cell Range object returned by the Worksheet.Range.get() method in Spire.XLS for JavaScript can be used to add formulas or functions to specified cells in an Excel worksheet. The main steps for adding formulas and functions to an Excel worksheet are as follows:
- Create a
Workbookobject. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Write data into cells and set the cell formatting.
- Use the
Range.Formulaproperty to add formulas and functions to the specified cells of the worksheet. - Use the
Workbook.SaveToFile()method to save the workbook.
Here is a complete code example showing how to insert mathematical operations, date functions, trigonometric functions, average functions, and sum functions into an Excel worksheet in React:
function App() {
const insertFormulasAndFunctions = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a Workbook object
const workbook = new xlsModule.Workbook();
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Declare two variables: currentRow and currentFormula
let currentRow = 1;
let currentFormula = "";
// Set the column width
sheet.SetColumnWidth(1, 32);
sheet.SetColumnWidth(2, 16);
// Write data into cells
sheet.Range.get({ row: currentRow, column: 1 }).Value = "Test Data";
sheet.Range.get({ row: currentRow, column: 2 }).NumberValue = 1;
sheet.Range.get({ row: currentRow, column: 3 }).NumberValue = 2;
sheet.Range.get({ row: currentRow, column: 4 }).NumberValue = 3;
sheet.Range.get({ row: currentRow, column: 5 }).NumberValue = 4;
sheet.Range.get({ row: currentRow, column: 6 }).NumberValue = 5;
currentRow += 2;
sheet.Range.get({ row: currentRow, column: 1 }).Value = "Formula or Function";
sheet.Range.get({ row: currentRow, column: 2 }).Value = "Result";
// Set the cell formatting
let range = sheet.Range.get({ row: currentRow, column: 1, lastRow: currentRow, lastColumn: 2 });
range.Style.Font.FontName = "Arial";
range.Style.KnownColor = xlsModule.ExcelColors.LightGreen;
range.Style.FillPattern = xlsModule.ExcelPatternType.Solid;
range.Style.Borders.get(xlsModule.BordersLineType.EdgeBottom).LineStyle = xlsModule.LineStyleType.Medium;
range.Style.Font.IsBold = true;
// Mathematical operation
currentFormula = "=1/2+3*4";
currentRow += 1;
sheet.Range.get({ row: currentRow, column: 1 }).NumberFormat = "@";
sheet.Range.get({ row: currentRow, column: 1 }).Text = currentFormula;
sheet.Range.get({ row: currentRow, column: 2 }).Formula = currentFormula;
// Date function
currentFormula = "=TODAY()";
currentRow += 1;
sheet.Range.get({ row: currentRow, column: 1 }).NumberFormat = "@";
sheet.Range.get({ row: currentRow, column: 1 }).Text = currentFormula;
sheet.Range.get({ row: currentRow, column: 2 }).Formula = currentFormula;
sheet.Range.get({ row: currentRow, column: 2 }).Style.NumberFormat = "YYYY/MM/DD";
// Trigonometric function
currentFormula = "=SIN(PI()/6)";
currentRow += 1;
sheet.Range.get({ row: currentRow, column: 1 }).NumberFormat = "@";
sheet.Range.get({ row: currentRow, column: 1 }).Text = currentFormula;
sheet.Range.get({ row: currentRow, column: 2 }).Formula = currentFormula;
// Average function
currentFormula = "=AVERAGE(B1:F1)";
currentRow += 1;
sheet.Range.get({ row: currentRow, column: 1 }).NumberFormat = "@";
sheet.Range.get({ row: currentRow, column: 1 }).Text = currentFormula;
sheet.Range.get({ row: currentRow, column: 2 }).Formula = currentFormula;
// Sum function
currentFormula = "=SUM(B1:F1)";
currentRow += 1;
sheet.Range.get({ row: currentRow, column: 1 }).NumberFormat = "@";
sheet.Range.get({ row: currentRow, column: 1 }).Text = currentFormula;
sheet.Range.get({ row: currentRow, column: 2 }).Formula = currentFormula;
// Save the workbook
const outputFileName = 'InsertFormulasAndFunctions_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Insert Formulas and Functions</h1>
<button onClick={insertFormulasAndFunctions}>
Start
</button>
</div>
);
}
export default App;
Insert formulas and function results into Excel worksheets

Read Formulas and Functions from an Excel Worksheet
To read formulas and functions from an Excel worksheet, you need to loop through all the used cells in the worksheet, then use the HasFormula property of a cell to find the cells that contain formulas or functions, and finally use the Range.Formula property to get the formulas or functions in those cells. The detailed steps are as follows:
- Create a
Workbookobject. - Use the
Workbook.LoadFromFile()method to load an Excel workbook. - Use the
Workbook.Worksheets.get()method to get the first worksheet. - Loop through the used cells in the worksheet.
- Use the
HasFormulaproperty to detect whether a cell contains a formula or function. If so, use theRange.RangeAddressLocalproperty and theRange.Formulaproperty to get the cell name and its formula or function, and output the retrieved content.
Here is a complete code example showing how to loop through a worksheet and read the formulas and functions in React:
function App() {
const readFormulasAndFunctions = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'FormulasAndFunctions.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Create a Workbook object
const workbook = new xlsModule.Workbook();
// Load the Excel workbook
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Get the used cell range of the worksheet
const usedRange = sheet.AllocatedRange;
// Create an output workbook
const output = new xlsModule.Workbook();
const outSheet = output.Worksheets.get(0);
let outRow = 1;
// Loop through the used cells
for (const cell of usedRange.Cells) {
// Check whether the cell contains a formula or function
if (cell.HasFormula) {
// Get the cell name
const cellname = cell.RangeAddressLocal;
// Get the formula or function in the cell
const formula = cell.Formula;
// Write the cell name and formula that were read
outSheet.Range.get({ row: outRow, column: 1 }).Value = "Cell " + cellname + " contains: " + formula;
outRow += 1;
}
}
// Set the output column width so the text displays completely
outSheet.SetColumnWidth(1, 45);
// Save the output workbook
const outputFileName = 'ReadFormulasAndFunctions_output.xlsx';
output.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
output.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Read Formulas and Functions</h1>
<button onClick={readFormulasAndFunctions}>
Start
</button>
</div>
);
}
export default App;
Read formulas and function results from Excel worksheets

Frequently Asked Questions
HasFormula cannot detect the formula, and the loop returns no results
Cause: The formula in the target cell was actually written as text (using the Text/Value property instead of the Formula property), and HasFormula only returns true for real formulas.
Solution: Make sure to use the Range.Formula property when inserting; otherwise, re-assign the text as a formula before reading.
Confusing the Formula and FormulaNumberValue properties
Cause: The Formula property returns the formula string in the cell, while the FormulaNumberValue property returns the numeric result after the formula is calculated. The two return different content.
Solution: Use cell.Formula when you need the formula string, and cell.FormulaNumberValue when you need the numeric result after calculation. Choose the appropriate property based on your actual needs.
Get a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
Group or Ungroup Rows and Columns in Excel with JavaScript in React
2026-09-04 08:50:04 Written by jie zouIn everyday Excel spreadsheet handling, grouping rows or columns lets you collapse detail data and show only summary information, making large tables cleaner and easier to read. Spire.XLS for JavaScript performs grouping and ungrouping directly in the browser based on WebAssembly, and manages input/output files through a virtual file system (VFS), with no backend service required.
This article covers two core features:
For installation and project configuration, refer to Integrate Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Group Rows or Columns
After grouping rows or columns, you can collapse the detail data inside a group and keep only the summary rows or columns you need, making the worksheet tidier. Spire.XLS for JavaScript groups rows with the GroupByRows() method and columns with the GroupByColumns() method. The main steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel document. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Use the
Worksheet.GroupByRows()method to group rows. - Use the
Worksheet.GroupByColumns()method to group columns. - Use the
Workbook.SaveToFile()method to save the document to a specified path.
Here is a complete code example showing how to group rows or columns in React:
function App() {
const groupRowsAndColumns = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'GroupRowsAndColumns.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Group rows
sheet.GroupByRows(6, 10, false);
sheet.GroupByRows(14, 16, false);
// Group columns
sheet.GroupByColumns(2, 7, false);
// Save the document
const outputFileName = 'GroupRowsAndColumns_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Group Rows And Columns</h1>
<button onClick={groupRowsAndColumns}>
Start
</button>
</div>
);
}
export default App;
After grouping, group markers appear on the left side of the grouped rows or above the grouped columns. Click a marker to collapse or expand the detail data.

Ungroup Rows or Columns
When the grouping structure is no longer needed, you can ungroup the existing groups so that all rows and columns return to their normal display. Spire.XLS for JavaScript ungroups rows with the UngroupByRows() method and columns with the UngroupByColumns() method. The main steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel document that contains groups. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Use the
Worksheet.UngroupByRows()method to ungroup rows. - Use the
Worksheet.UngroupByColumns()method to ungroup columns. - Use the
Workbook.SaveToFile()method to save the document to a specified path.
Here is a complete code example showing how to ungroup rows or columns in React:
function App() {
const ungroupRowsAndColumns = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'GroupRowsAndColumns.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Ungroup rows
sheet.UngroupByRows(6, 10);
sheet.UngroupByRows(14, 16);
// Ungroup columns
sheet.UngroupByColumns(2, 7);
// Save the document
const outputFileName = 'UngroupRowsAndColumns_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Ungroup Rows And Columns</h1>
<button onClick={ungroupRowsAndColumns}>
Start
</button>
</div>
);
}
export default App;
After ungrouping, the group markers on the rows or columns disappear and the data returns to the normal ungrouped display.

FAQ
Cannot collapse or expand detail data after grouping
Cause: The third parameter isCollapsed of the GroupByRows() and GroupByColumns() methods is set to false, so the groups are displayed expanded by default.
Solution: Set this parameter to true, and the groups will be displayed collapsed after saving:
sheet.GroupByRows(6, 10, true);
Some rows or columns still show group symbols after ungrouping
Cause: The UngroupByRows() and UngroupByColumns() methods only ungroup the rows or columns within the specified range. If these rows or columns also belong to a higher-level group, the higher-level group symbols are still retained.
Solution: Make sure the range passed when ungrouping matches the range used when grouping. If nested groups exist, call the ungroup methods repeatedly to ungroup level by level:
sheet.UngroupByRows(6, 10);
sheet.UngroupByRows(14, 16);
sheet.UngroupByColumns(2, 7);
Obtain a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
PDF has a fixed layout and is easy to distribute, but once its content has been generated, it is difficult to modify within the body text. For documents such as contracts, reports, and notices, you often need to indicate the confidentiality level, copyright ownership, or usage states such as "Draft" and "Sample" without affecting the reading of the body content. A text watermark is a common solution to this problem: it floats over the content as semi-transparent text, conveying the information clearly without harming the readability of the original.
Spire.PDF for JavaScript loads, draws, and saves PDFs directly in the browser via WebAssembly, managing input and output files through a virtual file system (VFS) without requiring a backend server. Text watermarking usually takes two forms: one places a single line of watermark text diagonally across the center of each page, which can be achieved directly through the transparency settings and coordinate-system transformations of the page canvas; the other tiles text repeatedly across the whole page, which can be done with the PdfTilingBrush tiling brush.
This article covers two core features:
For installation and project setup, refer to Integrating Spire.PDF for JavaScript in a React Project. The examples below assume Spire.PDF is installed and the WebAssembly module is initialized.
Add a Single-Line Text Watermark to PDF
A single-line text watermark places a line of diagonal text at the center of each page, suitable for marking confidentiality levels or copyright ownership. The approach is as follows: use a PdfTrueTypeFont based on a font that supports the characters you need, together with MeasureString, to measure the text size and compute the centering offset; then, page by page, set the transparency and rotate the coordinate system through SetTransparency, TranslateTransform, and RotateTransform; and finally draw the watermark text with DrawString.
function App() {
const addSingleLineTextWatermark = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the WASM module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load a TrueType font into VFS
await window.spire.FetchFileToVFS('ARIAL UNICODE MS.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the PDF file to be watermarked into VFS
const inputFileName = 'Lease_Agreement_EN.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Create a TrueType font: bold, 30 point
let trueTypeFont = new pdfModule.PdfTrueTypeFont({
fontFamily: 'Arial Unicode MS',
size: 30,
style: pdfModule.PdfFontStyle.Bold,
unicode: true
});
// Create the watermark brush and specify the watermark text
let brush = pdfModule.PdfBrushes.get_DarkGray();
const text = 'CONFIDENTIAL - DO NOT DISCLOSE';
// Measure the size of the watermark text
let textSize = trueTypeFont.MeasureString({ text: text });
// Compute two offsets to determine the coordinate translation, so that the watermark is centered diagonally
let offset1 = (textSize.Width * Math.sqrt(2)) / 4;
let offset2 = (textSize.Height * Math.sqrt(2)) / 4;
let format = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Left });
// Loop through all the pages in the document
for (let i = 0; i < doc.Pages.Count; i++) {
// Get the specified page
let page = doc.Pages.get_Item(i);
// Set the page transparency
page.Canvas.SetTransparency(0.8);
// Translate the coordinate system to the center of the page and compensate for the offset caused by the text size
page.Canvas.TranslateTransform(
page.Canvas.ClientSize.Width / 2 - offset1 - offset2,
page.Canvas.ClientSize.Height / 2 + offset1 - offset2
);
// Rotate the coordinate system counterclockwise by 45 degrees
page.Canvas.RotateTransform({ angle: -45 });
// Draw the watermark text on the page
page.Canvas.DrawString({ s: text, font: trueTypeFont, brush: brush, x: 0, y: 0, format: format });
}
// Define the output file name and save the document
const outputFileName = 'SingleLineTextWatermark.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Single-line Text Watermark To PDF</h1>
<button onClick={addSingleLineTextWatermark}>
Generate
</button>
</div>
);
}
export default App;
PDF document after adding the single-line text watermark

Add a Multiline Text Watermark to PDF
When you need the watermark to fill the entire page, use a multiline text watermark. The approach is as follows: use PdfTilingBrush to divide the page into tiling cells according to the page size; inside a cell, adjust the transparency and angle with SetTransparency and RotateTransform and draw the text with DrawString; finally fill the whole page with the brush using DrawRectangle.
function App() {
const addMultilineTextWatermark = async () => {
// Get the Spire.PDF WASM module
const pdfModule = window.wasmModule?.spirepdf;
// Check whether the WASM module is ready
if (!pdfModule) {
alert('Spire.PDF is not ready yet');
return;
}
// Load the PDF file to be watermarked into VFS
const inputFileName = 'Lease_Agreement_EN.pdf';
await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);
// Create a PdfDocument object and load the PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName);
// Get the first page of the document
let page = doc.Pages.get_Item(0);
// Create a tiling brush: use half the page width and one third of the page height as the tiling cell
let size = new pdfModule.SizeF({
width: page.Canvas.ClientSize.Width / 2,
height: page.Canvas.ClientSize.Height / 3
});
let brush = new pdfModule.PdfTilingBrush({ size: size });
// Set the watermark transparency to 30%
brush.Graphics.SetTransparency(0.3);
// Save the current state of the brush, then translate and rotate the coordinate system so that the watermark is arranged diagonally
brush.Graphics.Save();
brush.Graphics.TranslateTransform(brush.Size.Width / 2, brush.Size.Height / 2);
brush.Graphics.RotateTransform({ angle: -45 });
// Draw the tiled watermark
let format = new pdfModule.PdfStringFormat({ alignment: pdfModule.PdfTextAlignment.Center });
// Create font: bold, 25 point
let font = new pdfModule.PdfFont({ fontFamily: pdfModule.PdfFontFamily.Helvetica, size: 25 });
// Draw the watermark text
brush.Graphics.DrawString({
s: "CONFIDENTIAL",
font: font,
brush: pdfModule.PdfBrushes.get_DarkRed(),
x: 0,
y: -18,
format: format
});
// Restore the previous state of the brush and set it back to opaque
brush.Graphics.Restore();
brush.Graphics.SetTransparency({ alpha: 1 });
// Fill a whole-page rectangle with the tiling brush so that the watermark text tiles across the entire page
let rect = new pdfModule.RectangleF({
location: new pdfModule.PointF(0, 0),
size: page.Canvas.ClientSize
});
page.Canvas.DrawRectangle({ brush: brush, rectangle: rect });
// Define the output file name and save the document
const outputFileName = 'MultilineTextWatermark.pdf';
doc.SaveToFile(outputFileName);
doc.Close();
// Read the generated file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Multiline Text Watermark To PDF</h1>
<button onClick={addMultilineTextWatermark}>
Generate
</button>
</div>
);
}
export default App;
PDF document after adding the multiline text watermark

FAQ
How to set the font, size, and color of the watermark text
Reason: DrawString requires you to explicitly specify the font and brush used to draw the text.
Solution: The font, size, and color of the watermark text are determined by the font and brush passed to DrawString. For Latin text, create a PdfFont based on a built-in PdfFontFamily such as Helvetica, and set the color through the brush:
// Create a built-in font: Helvetica, 24 point
let font = new pdfModule.PdfFont({
fontFamily: pdfModule.PdfFontFamily.Helvetica,
size: 24
});
// Set the watermark color through the brush
let brush = pdfModule.PdfBrushes.get_DarkRed();
// Draw the watermark text on the page canvas
page.Canvas.DrawString({ s: 'CONFIDENTIAL', font: font, brush: brush, x: 0, y: 0, format: format });
If you need a font that is not built in — for example, to display non-Latin scripts such as Chinese or Japanese, or to apply a specific typeface — load the corresponding TrueType font into VFS and use PdfTrueTypeFont instead, as shown in the single-line text watermark example.
How to add a watermark to every page of a PDF
Reason: In the single-line text watermark example, a page loop applies the watermark to every page, while the multiline text watermark example only targets the first page through doc.Pages.get_Item(0).
Solution: To make the multiline watermark cover the entire document as well, move the creation of the tiling brush and the page fill into the page loop:
for (let i = 0; i < doc.Pages.Count; i++) {
let page = doc.Pages.get_Item(i);
// Create a tiling brush and set the transparency, rotation, and text
let size = new pdfModule.SizeF({
width: page.Canvas.ClientSize.Width / 2,
height: page.Canvas.ClientSize.Height / 3
});
let brush = new pdfModule.PdfTilingBrush({ size: size });
// …… set transparency, rotate, and draw the watermark text ……
// Fill the current page with the tiling brush
page.Canvas.DrawRectangle({
brush: brush,
rectangle: new pdfModule.RectangleF({ location: new pdfModule.PointF(0, 0), size: page.Canvas.ClientSize })
});
}
How to control the transparency and rotation angle of the watermark
Reason: Too high or too low transparency affects the appearance of the watermark, and the rotation angle determines the direction of the watermark text.
Solution: Use SetTransparency to set the transparency, whose value ranges from 0 (fully transparent) to 1 (opaque); use RotateTransform to control the coordinate-system rotation angle, where a negative value means counterclockwise rotation. The single-line example sets the transparency to 0.8 and rotates by -45 degrees, and the multiline tiling example makes the same settings within the graphics context of the tiling brush:
// Single-line watermark: set the page transparency and rotate the page canvas
page.Canvas.SetTransparency(0.8);
page.Canvas.RotateTransform({ angle: -45 });
// Multiline tiled watermark: set the transparency and rotation within the graphics context of the tiling brush
brush.Graphics.SetTransparency(0.3);
brush.Graphics.RotateTransform({ angle: -45 });
Get a Free License
If you want to remove the evaluation messages in the resulting documents or get rid of functional limitations, contact sales to obtain a 30-day temporary license.
Reading Excel files directly in a web application is useful for many scenarios, such as displaying spreadsheet data on a webpage, importing business records, analyzing worksheet content, or extracting specific data for further processing. In React applications, developers may also need to distinguish between different Excel data types, including text, numbers, formulas, dates, and Boolean values.
Spire.XLS for JavaScript provides APIs for loading and manipulating Excel files in JavaScript applications. With it, you can access worksheets and cells, retrieve different types of cell values, and extract embedded images without requiring Microsoft Excel. This article demonstrates how to read Excel files with JavaScript in React, including reading worksheet data, retrieving different cell value types, and extracting images.
On this page:
- Install Spire.XLS for JavaScript in a React Project
- Read Excel Data with JavaScript in React
- Read Different Types of Cell Data from Excel
- Read Images from Excel Worksheets
- Conclusion
- FAQs
Install Spire.XLS for JavaScript in a React Project
Before working with Excel files, install Spire.XLS for JavaScript in your React project.
Open a terminal in the project directory and run:
npm i spire.office
After installing the package, copy the required Spire.XLS JavaScript and WebAssembly runtime files to the public directory of the React project.
For detailed instructions on setting up the library and its WebAssembly runtime, refer to: How to Integrate Spire.XLS for JavaScript in a React Project
Once the runtime is configured, Excel files can be loaded into the Spire virtual file system and processed in the browser.
Read Excel Data with JavaScript in React
A common requirement when reading Excel files is to retrieve all used data from a worksheet and display it in a web interface.
Spire.XLS provides the AllocatedRange property to obtain the range of cells that are currently in use. You can then loop through its rows and columns and retrieve each cell's value.
The main steps are as follows:
- Load and initialize the Spire.XLS WebAssembly module.
- Load the Excel file into the Spire virtual file system.
- Create a
Workbookobject and load the Excel file. - Access the desired worksheet.
- Get the worksheet's allocated range.
- Iterate through the cells and retrieve their values.
- Store the extracted values in React state and display them in an HTML table.
The following example reads data from the first worksheet of an Excel file named Data.xlsx and displays the retrieved values in a React table.
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
const [tableData, setTableData] = useState([]);
const [status, setStatus] = useState('Loading Excel runtime...');
const [error, setError] = useState('');
useEffect(() => {
(async () => {
try {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(
/* webpackIgnore: true */
`${publicUrl}/spire.xls.js`
);
const xlsModule = spireModule.spirexls || window.spirexls;
if (!xlsModule) {
throw new Error('Spire XLS module was not initialized.');
}
window.wasmModule = xlsModule;
setWasmModule(xlsModule);
setStatus('Excel runtime ready.');
} catch (err) {
console.error('Failed to load Spire XLS runtime:', err);
setError(err.message || 'Failed to load Spire XLS runtime.');
setStatus('');
}
})();
}, []);
const loadExcelToVfs = async (fileName) => {
const publicUrl = process.env.PUBLIC_URL || '';
const response = await fetch(`${publicUrl}/${fileName}`);
if (!response.ok) {
throw new Error(
`Failed to load ${fileName}: ${response.status} ${response.statusText}`
);
}
if (!window.dotnetRuntime?.Module?.FS) {
throw new Error('Spire virtual file system is not ready.');
}
const fileBytes = new Uint8Array(await response.arrayBuffer());
window.dotnetRuntime.Module.FS.writeFile(
fileName,
fileBytes,
{ flags: 'w+' }
);
return fileName;
};
const readExcelData = async () => {
if (!wasmModule) {
setError('Excel runtime is not ready yet.');
return;
}
setError('');
setStatus('Reading Excel file...');
const workbook = new wasmModule.Workbook();
try {
const inputFile = await loadExcelToVfs('Data.xlsx');
workbook.LoadFromFile(inputFile);
const sheet = workbook.Worksheets.get(0);
const range = sheet.AllocatedRange;
const rows = [];
if (range) {
const firstRow = range.Row;
const firstColumn = range.Column;
const lastRow =
range.LastRow || firstRow + range.RowCount - 1;
const lastColumn =
range.LastColumn || firstColumn + range.ColumnCount - 1;
for (let r = firstRow; r <= lastRow; r++) {
const row = [];
for (let c = firstColumn; c <= lastColumn; c++) {
row.push(sheet.get(r, c).Value);
}
rows.push(row);
}
}
setTableData(rows);
setStatus(`Loaded ${rows.length} rows.`);
} catch (err) {
console.error('Failed to read Excel file:', err);
setError(err.message || 'Failed to read Excel file.');
setStatus('');
} finally {
workbook.Dispose();
}
};
return (
<div style={{ textAlign: 'center', padding: 30 }}>
<h1>Read Excel in JavaScript</h1>
<button onClick={readExcelData} disabled={!wasmModule}>
Read Excel File
</button>
{status && <p>{status}</p>}
{error && (
<p style={{ color: 'crimson' }}>
{error}
</p>
)}
{tableData.length > 0 && (
<table
border="1"
cellPadding="8"
style={{
margin: '20px auto',
borderCollapse: 'collapse'
}}
>
<tbody>
{tableData.map((row, ri) => (
<tr key={ri}>
{row.map((cell, ci) => (
<td key={ci}>{cell}</td>
))}
</tr>
))}
</tbody>
</table>
)}
</div>
);
}
export default App;
Code Explanation
The example first dynamically loads the Spire.XLS JavaScript runtime:
const spireModule = await import(
/* webpackIgnore: true */
`${publicUrl}/spire.xls.js`
);
const xlsModule = spireModule.spirexls || window.spirexls;
Since Spire.XLS uses a WebAssembly runtime, the source Excel file is then loaded into its virtual file system:
const fileBytes = new Uint8Array(await response.arrayBuffer());
window.dotnetRuntime.Module.FS.writeFile(
fileName,
fileBytes,
{ flags: 'w+' }
);
Next, create a Workbook object and load the Excel file:
const workbook = new wasmModule.Workbook();
workbook.LoadFromFile(inputFile);
The first worksheet can be accessed using:
const sheet = workbook.Worksheets.get(0);
To avoid iterating through unnecessary empty cells, the example retrieves the worksheet's used area through AllocatedRange:
const range = sheet.AllocatedRange;
The starting and ending rows and columns are then determined from this range. A nested loop is used to access each cell:
for (let r = firstRow; r <= lastRow; r++) {
const row = [];
for (let c = firstColumn; c <= lastColumn; c++) {
row.push(sheet.get(r, c).Value);
}
rows.push(row);
}
Finally, the resulting two-dimensional array is stored in the tableData React state and rendered as an HTML table.

This approach is useful when building spreadsheet viewers, Excel import interfaces, reporting pages, or other applications where worksheet data needs to be presented directly in the browser.
Read Different Types of Cell Data from Excel
Excel cells can contain different kinds of data. Depending on the content you need to retrieve, Spire.XLS provides different properties or methods for accessing the underlying cell value.
The following table lists some commonly used options:
| Data to Read | API |
|---|---|
| Text | cell.Text |
| Number | cell.NumberValue |
| Formula | cell.Formula |
| Formula calculation result | cell.FormulaValue |
| Date and time | cell.DateTimeValue |
| Boolean value | cell.BooleanValue |
| Number or text value | cell.Value |
| Date, Boolean, or other value | cell.Value2 |
For example, first access a particular cell:
const cell = sheet.get(rowIndex, colIndex);
You can then retrieve its content according to the expected data type.
Read Text
Use the Text property to retrieve the text representation of a cell:
const text = sheet.get(rowIndex, colIndex).Text;
This is useful when the displayed textual content of a cell is required.
Read Numbers
To obtain a numeric value, use NumberValue:
const number = sheet.get(rowIndex, colIndex).NumberValue;
This can be useful when worksheet values will be used for calculations or numeric processing in JavaScript.
Read Formulas and Formula Results
Excel cells may contain formulas rather than static values. The formula expression itself can be retrieved through the Formula property:
const formula = sheet.get(rowIndex, colIndex).Formula;
For example, a formula cell may contain an expression such as:
=SUM(B2:B10)
If you need the calculated result of the formula instead of the formula expression, use:
const formulaResult = sheet.get(rowIndex, colIndex).FormulaValue;
Being able to retrieve both the formula and its result is useful for spreadsheet analysis and auditing applications.
Read Dates
Excel stores date and time information as a specialized cell value. You can retrieve it using:
const date = sheet.get(rowIndex, colIndex).DateTimeValue;
The returned date value can then be formatted or processed according to the requirements of the React application.
Read Boolean Values
For cells containing Boolean values such as TRUE or FALSE, use:
const bool = sheet.get(rowIndex, colIndex).BooleanValue;
Read General Cell Values
When a cell may contain either a number or text, the Value property provides a convenient general-purpose option:
const value = sheet.get(rowIndex, colIndex).Value;
For values such as dates, Boolean values, or other underlying Excel data types, Value2 can also be used:
const value = sheet.get(rowIndex, colIndex).Value2;
Choosing the appropriate property based on the expected Excel data type makes it easier to preserve the original meaning of the worksheet content when processing it in JavaScript.
Read Images from Excel Worksheets
In addition to cell data, Excel worksheets can contain embedded pictures. Spire.XLS for JavaScript allows you to access these images through the worksheet's Pictures collection.
The following example retrieves the first picture from a worksheet and saves it as a PNG file:
let pic = sheet.Pictures.get(0);
const outputFileName = 'ReadImages-out.png';
pic.Picture.Save(outputFileName);
Because the image is saved inside the Spire WebAssembly virtual file system, it can then be read back into JavaScript:
const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
Next, create a JavaScript Blob from the resulting image data:
const modifiedFile = new Blob(
[modifiedFileArray],
{ type: 'image/png' }
);
The resulting Blob can be used for further browser-side operations. For example, you can create an object URL and display the extracted image directly in a React component:
const imageUrl = URL.createObjectURL(modifiedFile);
Then use the generated URL as the source of an HTML image element:
<img src={imageUrl} alt="Extracted from Excel" />
If a worksheet contains multiple pictures, you can iterate through the Pictures collection and process each image individually.
This capability is useful for applications that need to extract product images, logos, charts saved as pictures, document assets, or other visual content embedded in Excel worksheets.
Conclusion
Reading Excel files in React makes it possible to bring spreadsheet data directly into browser-based workflows. With Spire.XLS for JavaScript, developers can load Excel workbooks, access worksheets and used ranges, iterate through cells, and retrieve data without relying on Microsoft Excel.
In addition to general cell values, Spire.XLS allows JavaScript applications to access specific data types such as text, numbers, formulas, formula results, dates, and Boolean values. Embedded worksheet images can also be retrieved and converted into browser-compatible objects for display or further processing.
These features can be used to build Excel viewers, data import tools, reporting systems, spreadsheet analysis interfaces, and other React applications that need to work with Excel content.
FAQs
Can JavaScript Read Excel Files in a React Application?
Yes. JavaScript can read Excel files in React with the help of an Excel-processing library such as Spire.XLS for JavaScript. After loading the Excel file into the WebAssembly virtual file system, you can access its worksheets, cells, formulas, images, and other spreadsheet content directly in the browser.
How Do I Read All Used Cells in an Excel Worksheet?
You can use the worksheet's AllocatedRange property to determine the range that contains data. After obtaining its starting and ending rows and columns, iterate through the range and access individual cells using:
sheet.get(rowIndex, colIndex)
This avoids unnecessarily iterating through large areas of empty worksheet cells.
How Can I Read an Excel Formula and Its Calculated Result Separately?
Use the Formula property to retrieve the formula expression:
const formula = sheet.get(rowIndex, colIndex).Formula;
Use CalculatedValue when you need the calculated value of the formula:
const result = sheet.get(rowIndex, colIndex).FormulaValue;
This makes it possible to inspect both the formula logic and its resulting value.
Can I Extract Images from Excel with JavaScript?
Yes. Images embedded in a worksheet can be accessed through the Pictures collection. After retrieving a picture, you can save it to the Spire virtual file system, read the generated image bytes, and convert them into a JavaScript Blob. The Blob can then be displayed, downloaded, or processed further in the browser.
Get a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
Add, Read, Edit, and Delete Excel Comments with JavaScript in React
2026-09-04 03:58:32 Written by Lisa LiComments are an important tool in Excel for providing supplementary explanations of cell contents, and are commonly used in scenarios such as data review and collaborative notes. Spire.XLS for JavaScript uses WebAssembly to add, read, edit, and delete comments directly in the browser, managing input and output files through a virtual file system (VFS) — no backend server required.
This article covers several commonly used features:
For installation and project configuration, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Add a Comment
A comment can also carry author information, making it easy to identify where the comment comes from.
function App() {
const addCommentWithAuthor = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the Excel file into VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'CommentsSample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Get the cell where the comment will be added
const range = sheet.Range.get('C1');
// Set the author and comment content
const author = 'E-iceblue:';
const text = 'This is an example showing how to add a comment with an editable author property.';
// Add a comment to the cell and set its properties
const comment = range.AddComment();
comment.Width = 200;
comment.IsVisible = true;
comment.Text = author + ':\n' + text;
// Set the font style of the author name in the comment
const font = workbook.CreateFont();
font.FontName = 'Arial';
font.KnownColor = xlsModule.ExcelColors.Black;
font.IsBold = true;
comment.RichText.SetFont(0, author.length, font);
// Save the workbook
const outputFileName = 'AddCommentWithAuthor_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the generated file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Add Comment With Author</h1>
<button onClick={addCommentWithAuthor}>Start</button>
</div>
);
}
export default App;
After running, a comment containing the author name and the comment text will appear on cell C1. 
Read Comment Content
You can read the comment on a cell through the CellRange.Comment property.
function App() {
const readComment = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the Excel file into VFS
const inputFileName = 'CommentsSample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Get the comment text
const builder = [];
builder.push(sheet.Range.get('A1').Comment.Text + '\n\t');
builder.push(sheet.Range.get('A2').Comment.Text);
// Save the comment content to a txt file
const outputFileName = 'ReadComment_output.txt';
window.dotnetRuntime.Module.FS.writeFile(outputFileName, builder.join('\n'));
workbook.Dispose();
// Read the generated file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Read Comment</h1>
<button onClick={readComment}>Start</button>
</div>
);
}
export default App;
The read comment content 
Edit Comment Content
Get a comment by index through Comments.get(0), and then modify its text content.
function App() {
const editComment = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the Excel file into VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'CommentsSample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Get the first comment
const comment = sheet.Comments.get(0);
// Edit the comment content
comment.Text = 'This comment has been edited by Spire.XLS.';
// Save the workbook
const outputFileName = 'EditExcelComment_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the generated file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Edit Excel Comment</h1>
<button onClick={editComment}>Start</button>
</div>
);
}
export default App;
The edited comment content 
Delete Comments
You can delete all comments in a worksheet through the Comments.Clear method.
function App() {
const removeComment = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the Excel file into VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'CommentsSample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get all comments of the first worksheet
const comments = workbook.Worksheets.get(0).Comments;
// Clear all comments; alternatively, use comments.RemoveAt(0) to delete a comment by index
comments.Clear();
// Save the workbook
const outputFileName = 'RemoveComment_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the generated file from VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Remove Comment</h1>
<button onClick={removeComment}>Start</button>
</div>
);
}
export default App;
After deleting comments 
FAQ
Comment is not visible after being added
Cause: The IsVisible property was not set to true after adding the comment, so the comment remains hidden by default.
Solution: Set comment.IsVisible = true after adding the comment to make it visible in the worksheet.
Empty content is returned when reading a comment
Cause: There is no comment on the target cell, or an incorrect cell reference was used.
Solution: Confirm that the target cell has a comment, and access the comment content through methods such as sheet.Range.get('A1').Comment.
Get a Free License
If you want to remove the evaluation messages in the resulting documents, or get rid of functional limitations, please contact sales to obtain a temporary license valid for 30 days.
Set Excel Background Color and Background Image with JavaScript in React
2026-09-02 09:38:17 Written by jie zouWhen creating reports, setting background colors for cells highlights headers and key data, and setting a background image for the worksheet makes the whole report more recognizable. Spire.XLS for JavaScript performs both kinds of settings directly in the browser based on WebAssembly, and manages input/output files through a virtual file system (VFS), with no backend service required.
This article covers two core features:
For installation and project configuration, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Set Cell Background Color
Setting a background color for cells highlights headers, important data, or specific regions. Spire.XLS for JavaScript sets a background color for a cell or a cell range through the CellRange.Style.Color property, with rich built-in colors supported. The main steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel document. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Use the
CellRange.Style.Colorproperty to set a background color for a specific cell range. - Use the
Workbook.SaveToFile()method to save the document to a specified path.
Here is a complete code example showing how to set background colors for cell ranges in React:
function App() {
const setBackgroundColor = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'SetBackgroundColor.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Set the header row to a yellow background
sheet.Range.get("A1:E1").Style.Color = xlsModule.Color.get_Yellow();
// Set the first two data rows to a light sky blue background
sheet.Range.get("A2:E2").Style.Color = xlsModule.Color.get_LightSkyBlue();
sheet.Range.get("A3:E3").Style.Color = xlsModule.Color.get_LightSkyBlue();
// Save the document
const outputFileName = 'SetBackgroundColor_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Set Cell Background Color</h1>
<button onClick={setBackgroundColor}>
Start
</button>
</div>
);
}
export default App;
After setting the background colors, the header row is displayed with a yellow background and the first two data rows with a light sky blue background, making it easy to distinguish cells in different regions.

Set Worksheet Background Image
In addition to setting background colors for cells, you can also set a background image for the whole worksheet to make the report more recognizable. Spire.XLS for JavaScript sets an image as the worksheet background through the Worksheet.PageSetup.BackgroundImage property. The main steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel document. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Use a
Streamobject to read the image file to be used as the background. - Use the
Worksheet.PageSetup.BackgroundImageproperty to set the image as the worksheet background. - Use the
Workbook.SaveToFile()method to save the document to a specified path.
Here is a complete code example showing how to set a background image for a worksheet in React:
function App() {
const setBackgroundImage = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font, image, and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const backgroundImageName = 'Background.png';
await window.spire.FetchFileToVFS(backgroundImageName, '', `${process.env.PUBLIC_URL}data/`);
const inputFileName = 'SetBackgroundColor.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Open the image as a stream
const bm = new xlsModule.Stream(backgroundImageName);
// Set the image as the worksheet background
sheet.PageSetup.BackgroundImage = bm;
// Save the document
const outputFileName = 'SetBackgroundImage_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Set Worksheet Background Image</h1>
<button onClick={setBackgroundImage}>
Start
</button>
</div>
);
}
export default App;
After setting the background image, the image fills the back of the worksheet as its background, while the cell contents and data remain clearly displayed on top of the image.

FAQ
The background color is lost after saving and reopening
Cause: The Style.Color property sets the background (fill) color of a cell, not the font color. If the color is overridden by other styles, or the fill pattern is not set correctly, the color may not display properly.
Solution: Set the color directly for the cell range, for example sheet.Range.get("A1:E1").Style.Color = xlsModule.Color.get_Yellow();. If you want to use a patterned fill, combine Style.Interior.FillPattern and Style.Interior.Gradient.
The background image does not appear above the data
Cause: A worksheet background image is always displayed behind the cell contents and only serves as background decoration. It neither covers the data nor is covered by it.
Solution: This is the normal display layering. If you need the image to appear on top of the data, use the Worksheet.Pictures.Add() method to insert a floating image in the worksheet instead of setting a worksheet background.
Obtain a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
In everyday Excel data processing, sorting is one of the most common operations — whether rearranging data by name, value, or date, it makes tables more organized and easier to search. Spire.XLS for JavaScript performs data sorting directly in the browser based on WebAssembly, and manages input/output files through a virtual file system (VFS), with no backend service required.
This article covers two core features:
For installation and project configuration, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Sort Data in a Cell Range in Ascending Order
Sorting a specified cell range in ascending order is the most common data arrangement requirement. Spire.XLS for JavaScript adds a sort field and specifies the sort order with the Workbook.DataSorter.SortColumns.Add() method, then sorts the specified range with the Workbook.DataSorter.Sort() method. The main steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel document. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Use the
Workbook.DataSorter.SortColumns.Add()method to add a sort field, specifying the column and the sort order. - Use the
Workbook.DataSorter.Sort()method to sort the specified cell range. - Use the
Workbook.SaveToFile()method to save the document to a specified path.
Here is a complete code example showing how to sort a cell range in ascending order by a single column in React:
function App() {
const sortAscending = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'DataSorting.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Add a sort field: sort by the 5th column (Population) in ascending order
workbook.DataSorter.SortColumns.Add({ key: 4, orderBy: xlsModule.OrderBy.Ascending });
// Sort the specified cell range A1:E19
workbook.DataSorter.Sort(sheet.Range.get("A1:E19"));
// Save the document
const outputFileName = 'SortDataAscending_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Sort Data in Ascending Order</h1>
<button onClick={sortAscending}>
Start
</button>
</div>
);
}
export default App;
After sorting, the data is rearranged in ascending numerical order based on the 5th column (Population), from the smallest to the largest, and the other columns in the same row stay aligned with the Population column.

Sort Data by Multiple Columns
When a single-column sort is not enough, you can sort by multiple columns at the same time. Spire.XLS for JavaScript supports adding multiple sort fields by calling the SortColumns.Add() method several times. Data is sorted by the first field first, then by the subsequent fields. The main steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel document. - Use the
Workbook.Worksheets.get()method to get a specific worksheet. - Call the
Workbook.DataSorter.SortColumns.Add()method several times to add multiple sort fields. - Use the
Workbook.DataSorter.Sort()method to sort the specified cell range. - Use the
Workbook.SaveToFile()method to save the document to a specified path.
Here is a complete code example showing how to sort a cell range by multiple columns in React:
function App() {
const sortMultipleColumns = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'DataSorting.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Add multiple sort fields: first by the 3rd column (Continent), then by the 4th column (Area), ascending
workbook.DataSorter.SortColumns.Add({ key: 2, orderBy: xlsModule.OrderBy.Ascending });
workbook.DataSorter.SortColumns.Add({ key: 3, orderBy: xlsModule.OrderBy.Ascending });
// Sort the specified cell range A1:E19
workbook.DataSorter.Sort(sheet.Range.get("A1:E19"));
// Save the document
const outputFileName = 'SortDataMultipleColumns_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Sort Data by Multiple Columns</h1>
<button onClick={sortMultipleColumns}>
Start
</button>
</div>
);
}
export default App;
After sorting, the data is first arranged in ascending order by the 3rd column (Continent), grouping countries from the same continent together; when the continents are the same, it is then sorted in ascending order by the 4th column (Area).

FAQ
The header row is also included in the sorting
Cause: By default, the DataSorter.Sort() method treats the first row of the sort range as a title row and keeps it in place. If the header is moved into the data rows, it is usually because the starting row of the sort range is set incorrectly.
Solution: Make sure the range passed to the Sort() method includes the header row and that the header row is at the top of the range, for example sheet.Range.get("A1:E19"). You can also start the sort from the data rows, such as sheet.Range.get("A2:E19").
After a single-column sort, other columns do not change accordingly
Cause: The sort only takes effect on the cell range passed to the Sort() method. If you sort only a single column's range, the other columns will not be rearranged, causing data in the same row to become misaligned.
Solution: Make the sort range cover all related columns (for example, the complete range that includes name, capital, continent, area, and population, A1:E19), so that the entire row moves together.
Obtain a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.
Finding and replacing data is a common requirement when processing Excel files in web applications. Spire.XLS for JavaScript runs entirely in the browser via WebAssembly, using a virtual file system (VFS) to manage input and output files — no backend server required. It provides search methods such as FindAllString() and FindAllNumber() that let you locate target data across an entire worksheet or within a specified cell range, quickly replace it with new content, and optionally mark the replaced cells with a highlight color.
With Spire.XLS for JavaScript, you can batch-replace text across an entire worksheet or restrict the search to a specific cell range, giving you both efficiency and flexibility when updating partial data precisely.
This article covers two core features:
- Find and Replace Data in a Worksheet in Excel
- Find and Replace Data in a Specific Cell Range in Excel
For installation and project setup, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Find and Replace Data in a Worksheet in Excel
With Spire.XLS for JavaScript, you can find all cells containing a specified text in an entire worksheet and replace them with new content. The FindAllString() method returns all matching cell ranges. You can then replace the text by setting the range.Text property and highlight the replaced cells by setting the range.Style.Color property, making it easy to identify where modifications were made. The steps are as follows:
- Create a
Workbookobject and load an existing Excel file. - Get the worksheet to operate on via
workbook.Worksheets.get(). - Use
worksheet.FindAllString()to find all cell ranges containing the specified text in the worksheet. - Iterate through the search results, replacing the text via
range.Textand setting the highlight color viarange.Style.Color. - Save the workbook to an Excel file using
SaveToFile().
Below is a complete code example demonstrating how to find and replace data across an entire worksheet in React:
function App() {
const findAndReplace = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
let excelFileName = 'Sample.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}static/data/`);
// Create a new workbook and load an existing Excel file
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// Get the first worksheet
let worksheet = workbook.Worksheets.get(0);
// Find all cells containing the text "Total" in the worksheet
let ranges = worksheet.FindAllString("Total", false, false);
// Iterate through the search results, replace the text, and set the highlight color
for (let range of ranges) {
range.Text = "Total Expenses";
range.Style.Color = xlsModule.Color.get_Yellow();
}
// Save the workbook
const outputFileName = 'FindAndReplaceData.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
workbook.Dispose();
// Read the file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Find and Replace Data in a Worksheet</h1>
<button onClick={findAndReplace}>
Generate
</button>
</div>
);
}
export default App;
Find and replace data in a worksheet in Excel

Find and Replace Data in a Specific Cell Range in Excel
When you only need to update part of the data, you can restrict the search to a specific cell range. After specifying the target range with the sheet.Range.get() method, range.FindAllString() searches for cells containing the specified text only within that range, ensuring that data outside the range remains unaffected. The steps are as follows:
- Create a
Workbookobject and load an existing Excel file. - Get the worksheet to operate on via
workbook.Worksheets.get(). - Specify the cell range to search with
sheet.Range.get(). - Use
range.FindAllString()to find cells containing the target text within the specified range, then iterate through the results to replace the text and set the highlight color. - Save the workbook to an Excel file using
SaveToFile().
Below is a complete code example demonstrating how to find and replace data in a specific cell range in React:
function App() {
const findAndReplaceInRange = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the sample file into the Virtual File System (VFS)
let excelFileName = 'FindCellsSample.xlsx';
await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}static/data/`);
// Create a new workbook and load an existing Excel file
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: excelFileName });
// Get the first worksheet
let worksheet = workbook.Worksheets.get(0);
// Specify the cell range to search
let range = worksheet.Range.get({
row: 1,
column: 1,
lastRow: 12,
lastColumn: 2,
});
// Find all cells containing the text "Total" within the specified range
let ranges = range.FindAllString("Total", false, false);
// Iterate through the search results, replace the text, and set the highlight color
for (let r of ranges) {
r.Text = "Total Expenses";
r.Style.Color = xlsModule.Color.get_Yellow();
}
// Save the workbook
const outputFileName = 'FindAndReplaceInRange.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
workbook.Dispose();
// Read the file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Find and Replace Data in a Specific Cell Range</h1>
<button onClick={findAndReplaceInRange}>
Generate
</button>
</div>
);
}
export default App;
Find and replace data in a specific cell range in Excel

FAQ
How to control whether the search is case-sensitive or matches whole words
Cause: The last two boolean parameters of the FindAllString() method control whether the search is case-sensitive and whether it must match whole words. If these parameters are set incorrectly, you may find too many or too few matching results.
Solution: Adjust the parameters of FindAllString() according to your actual needs:
// Case-insensitive, whole-word matching not required
let ranges = worksheet.FindAllString("Area", false, false);
// Case-sensitive, whole-word matching required
let ranges = worksheet.FindAllString("Total", true, true);
How to find and replace numbers in a specific range
Cause: Find and replace works not only with text but also with numbers. If you only use FindAllString() to handle text, numeric cells cannot be matched.
Solution: Use the range.FindAllNumber() method to find numbers within the specified range, then replace the values by setting the Text property:
let numberRanges = range.FindAllNumber(100, true);
for (let r of numberRanges) {
r.Text = "200";
r.Style.Color = xlsModule.Color.get_Yellow();
}
Get a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.

TL;DR: Learn how to convert Markdown files and strings into HTML directly inside the browser using JavaScript and Spire.Doc WebAssembly (WASM) in React. No server-side processing required.
Markdown is commonly used for README files, documentation, technical articles, and other structured content. However, some applications need the content as an actual HTML file—for example, to publish it as a web page or pass it to another HTML-based workflow.
This article shows how to convert Markdown to HTML with JavaScript in a React application using Spire.Doc for JavaScript. It covers two common scenarios:
Prerequisites & Project Setup
Step 1: Install Spire.Doc for JavaScript
Open a terminal in the root directory of your React project and install the Spire.Doc package through NPM:
npm i spire.office
Step 2: Copy the Runtime Resources
After installation, copy the following runtime resources from node_modules/spire.office to the public directory of your React project:
- _framework
- spire.doc.js
- Spire.Doc.Wasm.zip
- spire.common.js
- Spire.Common.Wasm.zip
The examples also use CALIBRI.ttf for text rendering. Place the font file under public/static/font/.
For the file-based example, place the source Markdown document in public/static/data/MarkdownExample.md.
For detailed setup instructions, see How to Integrate Spire.Doc for JavaScript in a React Project.
Note: The examples use
process.env.PUBLIC_URL, which follows the Create React App convention. If your project uses Vite or another build tool, adjust the public asset paths accordingly.
Convert a Markdown File to HTML with JavaScript in React
If the Markdown content already exists as a .md file, it can be loaded into the WebAssembly virtual file system (VFS) and opened directly with Document.LoadFromFile(). The document can then be exported as HTML using Document.SaveToFile().
The file-based conversion follows four main stages:
- Module Initialization: Load and initialize the Spire.Doc WebAssembly module when the React component mounts.
- Input Loading: Add the required font and source Markdown file to the VFS using
FetchFileToVFS(). - Document Conversion: Load the
.mdfile withFileFormat.Markdownand save it withFileFormat.Html. - Output Handling: Read the generated HTML from the VFS and download it in the browser.
The following example converts MarkdownExample.md to MarkdownToHtml.html.
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
// Load Spire.Doc
useEffect(() => {
(async () => {
try {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(
/* webpackIgnore: true */
`${publicUrl}/spire.doc.js`
);
const rawModule = spireModule.default || spireModule;
window.wasmModule =
typeof rawModule === 'function'
? await rawModule({
locateFile: (path) =>
path.endsWith('.wasm')
? `${publicUrl}/${path}`
: path
})
: rawModule;
setWasmModule(window.wasmModule);
} catch (error) {
console.error(
'Failed to load spire.doc.js WASM module:',
error
);
}
})();
}, []);
// Convert Markdown file to HTML
const convertMarkdownFileToHtml = async () => {
const wasmModule = window.wasmModule?.spiredoc;
if (!wasmModule) return;
// Load the required font into the VFS
await window.spire.FetchFileToVFS(
'CALIBRI.ttf',
'/Library/Fonts/',
`${process.env.PUBLIC_URL}/static/font/`
);
// Load the Markdown file into the VFS
const inputFileName = 'MarkdownExample.md';
await window.spire.FetchFileToVFS(
inputFileName,
'',
`${process.env.PUBLIC_URL}/static/data/`
);
// Create a Document instance
const doc = new wasmModule.Document();
try {
// Load the Markdown document
doc.LoadFromFile({
fileName: inputFileName,
fileFormat: wasmModule.FileFormat.Markdown
});
// Set HTML export options
doc.HtmlExportOptions.CssStyleSheetType = wasmModule.CssStyleSheetType.Internal;
doc.HtmlExportOptions.ImageEmbedded = true;
// Save the document as HTML
const outputFileName = 'MarkdownToHtml.html';
doc.SaveToFile({
fileName: outputFileName,
fileFormat: wasmModule.FileFormat.Html
});
// Read the generated HTML from the VFS
const htmlBytes =
window.dotnetRuntime.Module.FS.readFile(
outputFileName
);
// Download the HTML file
const blob = new Blob(
[htmlBytes],
{ type: 'text/html;charset=utf-8' }
);
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = outputFileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
} finally {
doc.Dispose();
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Convert Markdown File to HTML</h1>
<button
onClick={convertMarkdownFileToHtml}
disabled={!wasmModule}
>
Convert and Download
</button>
</div>
);
}
export default App;
Once the WebAssembly module has loaded, click Convert and Download. The application loads MarkdownExample.md from public/static/data/, converts it to HTML, and downloads the generated MarkdownToHtml.html file.
Here, FetchFileToVFS() loads the source Markdown file into the WebAssembly virtual file system, and Document.LoadFromFile() reads the file from the VFS. CssStyleSheetType.Internal and ImageEmbedded embed styles and images directly in the HTML, while Document.SaveToFile() exports the document as HTML.
Output:

Convert a Markdown String to HTML with JavaScript in React
Markdown is also frequently generated or edited directly inside an application. Content returned by an API or CMS, for example, may already be available as a JavaScript string rather than an existing .md file.
Since Document.LoadFromFile() works with files available in the WebAssembly virtual file system, a Markdown string can first be written to a temporary .md file with FS.writeFile(). The temporary file can then be processed in the same way as a regular Markdown document.
The string-based conversion follows five main steps:
- Module Initialization: Load and initialize the Spire.Doc WebAssembly module.
- Content Preparation: Define or retrieve the Markdown string.
- VFS Creation: Write the Markdown string to a temporary
.mdfile usingFS.writeFile(). - Document Conversion: Load the virtual Markdown file and save it as HTML.
- Output Handling: Read the HTML file from the VFS and download or process it as needed.
The following example converts a Markdown string containing headings, lists, code, links, and a table.
import React, { useState, useEffect } from 'react';
function App() {
const [wasmModule, setWasmModule] = useState(null);
// Load Spire.Doc
useEffect(() => {
(async () => {
try {
const publicUrl = process.env.PUBLIC_URL || '';
const spireModule = await import(
/* webpackIgnore: true */
`${publicUrl}/spire.doc.js`
);
const rawModule = spireModule.default || spireModule;
window.wasmModule =
typeof rawModule === 'function'
? await rawModule({
locateFile: (path) =>
path.endsWith('.wasm')
? `${publicUrl}/${path}`
: path
})
: rawModule;
setWasmModule(window.wasmModule);
} catch (error) {
console.error(
'Failed to load spire.doc.js WASM module:',
error
);
}
})();
}, []);
// Convert Markdown string to HTML
const convertMarkdownStringToHtml = async () => {
const wasmModule = window.wasmModule?.spiredoc;
if (!wasmModule) return;
// Load the required font into the VFS
await window.spire.FetchFileToVFS(
'CALIBRI.ttf',
'/Library/Fonts/',
`${process.env.PUBLIC_URL}/static/font/`
);
// Define the Markdown string
const markdownString = `# Project Documentation
This project provides a **browser-based document converter**.
## Features
- Convert Markdown to HTML
- Process content in the browser
- Export the generated HTML
## Code Example
\`\`\`javascript
function greet(name) {
console.log(\`Hello, \${name}!\`);
}
greet("World");
\`\`\`
## Supported Content
| Feature | Supported |
|---------|-----------|
| Headings | Yes |
| Lists | Yes |
| Tables | Yes |
| Links | Yes |
Visit [Example.com](https://example.com) for more information.
`;
const inputFileName = 'MarkdownString.md';
const outputFileName = 'MarkdownStringToHtml.html';
// Write the Markdown string to the VFS
window.dotnetRuntime.Module.FS.writeFile(
inputFileName,
markdownString,
{ encoding: 'utf8' }
);
// Create a Document instance
const doc = new wasmModule.Document();
try {
// Load the Markdown document
doc.LoadFromFile({
fileName: inputFileName,
fileFormat: wasmModule.FileFormat.Markdown
});
// Set HTML export options
doc.HtmlExportOptions.CssStyleSheetType = wasmModule.CssStyleSheetType.Internal;
doc.HtmlExportOptions.ImageEmbedded = true;
// Save the document as HTML
doc.SaveToFile({
fileName: outputFileName,
fileFormat: wasmModule.FileFormat.Html
});
// Read the generated HTML from the VFS
const htmlBytes =
window.dotnetRuntime.Module.FS.readFile(
outputFileName
);
// Download the HTML file
const blob = new Blob(
[htmlBytes],
{ type: 'text/html;charset=utf-8' }
);
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = outputFileName;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
} finally {
doc.Dispose();
}
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Convert Markdown String to HTML</h1>
<button
onClick={convertMarkdownStringToHtml}
disabled={!wasmModule}
>
Convert and Download
</button>
</div>
);
}
export default App;
Unlike the previous example, there is no source .md file to load. The Markdown content is written directly to the VFS with FS.writeFile().
window.dotnetRuntime.Module.FS.writeFile(
inputFileName,
markdownString,
{ encoding: 'utf8' }
);
This approach also works with Markdown returned from an API, database, CMS, or text editor. Instead of defining markdownString directly in the code, pass the retrieved Markdown content to FS.writeFile().
Output:

Troubleshooting Common MD to HTML Issues
Most conversion problems in a React JavaScript project relate to WebAssembly initialization, public asset paths, or files not loaded into the VFS correctly. The table below lists the most common issues and what to check first.
| Issue | Possible Cause | What to Check |
|---|---|---|
spiredoc is undefined |
The conversion starts before WASM initialization finishes | Keep the conversion button disabled until wasmModule is available |
| 404 when loading runtime files | One or more Spire.Doc assets are missing or the public path is incorrect | Check spire.doc.js, _framework/, WASM resources, and the browser Network panel |
MarkdownExample.md cannot be loaded |
The source file path passed to FetchFileToVFS() is incorrect |
Verify that the file is available under public/static/data/ |
| Font loading fails | CALIBRI.ttf is missing or the font path is incorrect |
Confirm that the font is accessible under public/static/font/ |
| Conversion works locally but fails after deployment | The deployed application uses a different public base path | Verify the generated URLs and adjust process.env.PUBLIC_URL or the equivalent build-tool setting |
| Browser memory increases after repeated conversions | Document objects are not released | Call doc.Dispose() after each conversion, preferably in a finally block |
FAQs
Q: How do I convert a user-selected Markdown file to HTML?
A: A file selected through <input type="file"> is different from a Markdown file stored in the application's public assets.
Read the selected file with the browser File API:
const markdownString = await file.text();
Then write the string to the VFS with FS.writeFile() and use the same conversion process shown in the Markdown string example.
Q: Can I preview the generated HTML instead of downloading it?
A: Yes. Read the generated HTML from the VFS and decode the returned bytes:
const htmlBytes = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const html = new TextDecoder('utf-8').decode(htmlBytes);
The resulting string can then be displayed with an iframe:
<iframe
title="HTML Preview"
srcDoc={html}
/>
Security Note: If the Markdown comes from untrusted users or external sources, treat the generated HTML as untrusted content as well and sanitize or isolate it before rendering it in a production application.
Q: Does Markdown-to-HTML conversion require a backend?
A: No. In the examples above, document processing runs through WebAssembly in the browser. The source Markdown and generated HTML are handled through the client-side virtual file system.
A backend may still be needed if your application needs to store the generated file, retrieve protected source content, or perform other server-side operations.
Conclusion
This article showed how to convert Markdown to HTML with JavaScript in React, covering both Markdown files and Markdown strings. By running the conversion through WebAssembly in the browser, content from files, editors, APIs, or CMS platforms can be turned into HTML for download, preview, or further processing. The same core conversion logic can be reused across different Markdown sources.
Create, Filter, and Update Excel Pivot Tables with JavaScript in React
2026-09-01 06:41:05 Written by Lisa LiA pivot table (PivotTable) is a core tool in Excel for quickly summarizing and analyzing large amounts of data. By dragging and dropping fields, you can easily perform data statistics and comparisons. Spire.XLS for JavaScript is based on WebAssembly and can create, filter, and update pivot tables directly in the browser. It manages input and output files through a virtual file system (VFS), so no backend services are required.
This article covers three core features:
For installation and project configuration, please refer to How to Integrate Spire.XLS for JavaScript in a React Project. The examples below assume that Spire.XLS is installed and the WebAssembly module has been initialized.
Create a Pivot Table
Creating a pivot table usually involves four steps: preparing the source data, adding a pivot table, laying out the fields, and calculating the data. The following example writes a product sales record into the first worksheet, creates a cache based on the data range using the PivotCaches.Add method, adds a pivot table to the worksheet using the PivotTables.Add method, and finally drags fields into the row area and the data area to complete the layout.
function App() {
const createPivotTable = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook
const workbook = new xlsModule.Workbook();
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Write source data to cells
sheet.Range.get('A1').Value = 'Product';
sheet.Range.get('B1').Value = 'Month';
sheet.Range.get('C1').Value = 'Count';
sheet.Range.get('A2').Value = 'SpireDoc';
sheet.Range.get('A3').Value = 'SpireDoc';
sheet.Range.get('A4').Value = 'SpireXls';
sheet.Range.get('A5').Value = 'SpireDoc';
sheet.Range.get('A6').Value = 'SpireXls';
sheet.Range.get('A7').Value = 'SpireXls';
sheet.Range.get('B2').Value = 'January';
sheet.Range.get('B3').Value = 'February';
sheet.Range.get('B4').Value = 'January';
sheet.Range.get('B5').Value = 'January';
sheet.Range.get('B6').Value = 'February';
sheet.Range.get('B7').Value = 'February';
sheet.Range.get('C2').Value = '10';
sheet.Range.get('C3').Value = '15';
sheet.Range.get('C4').Value = '9';
sheet.Range.get('C5').Value = '7';
sheet.Range.get('C6').Value = '8';
sheet.Range.get('C7').Value = '10';
// Create a pivot table cache based on the data range
const dataRange = sheet.Range.get('A1:C7');
const cache = workbook.PivotCaches.Add({ range: dataRange });
// Add a pivot table
const pt = sheet.PivotTables.Add('Pivot Table', sheet.Range.get({ row: 10, column: 5 }), cache);
// Drag fields into the row area
const pf1 = pt.PivotFields.get_Item('Product');
pf1.Axis = xlsModule.AxisTypes.Row;
const pf2 = pt.PivotFields.get_Item('Month');
pf2.Axis = xlsModule.AxisTypes.Row;
// Drag fields into the data area
pt.DataFields.Add(pt.PivotFields.get_Item('Count'), 'Sum of Count', xlsModule.SubtotalTypes.Sum);
// Set the pivot table style
pt.BuiltInStyle = xlsModule.PivotBuiltInStyles.PivotStyleMedium12;
// Calculate the pivot table data
pt.CalculateData();
sheet.AutoFitColumn(5);
sheet.AutoFitColumn(6);
// Save the workbook
const outputFileName = 'CreatePivotTable_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Create Pivot Table</h1>
<button onClick={createPivotTable}>Start</button>
</div>
);
}
export default App;
After calculating with the CalculateData method, the pivot table summarizes the total count of each product by product and month, displayed with the set PivotStyleMedium12 style.

Filter a Pivot Table
When a pivot table contains a lot of data, you can add filters to the row fields to keep only the data rows that meet the conditions.
function App() {
const filterPivotTable = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'PivotTableExample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Get the first pivot table in the second worksheet (PivotTable)
const pt = workbook.Worksheets.get(1).PivotTables.get(0);
// Get the first row field of the pivot table
const rowField = pt.RowFields.get(0);
// Add a value filter to the row field: values of the first data field less than 5300000
rowField.AddValueFilter(xlsModule.PivotValueFilterType.LessThan, pt.DataFields.get(0), window.spire.Double.Create(5300000), new window.spire.SpireObject(0));
// Recalculate the pivot table data
pt.CalculateData();
// Save the workbook
const outputFileName = 'FilterPivotTable_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Filter Pivot Table</h1>
<button onClick={filterPivotTable}>Start</button>
</div>
);
}
export default App;
Original pivot table data 
After filtering, the row area of the pivot table keeps only the data that meets the filter conditions, making it easy to focus on analyzing data in a specific range. 
Update the Data Source and Refresh the Pivot Table
When the underlying data of a pivot table changes, you need to update the data source and refresh the pivot table cache so that the pivot table reflects the latest summary results.
function App() {
const updateDataSource = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check if the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font and the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'PivotTableExample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Get the data source worksheet and modify the cell values in it
const data = workbook.Worksheets.get('Data');
data.Range.get('A2').Text = 'NewValue';
data.Range.get('D2').NumberValue = 28000;
// Get the worksheet that contains the pivot table
const sheet = workbook.Worksheets.get({ sheetName: 'PivotTable' });
// Get the first pivot table on the worksheet
const pt = sheet.PivotTables.get(0);
// Refresh the pivot table cache
pt.Cache.IsRefreshOnLoad = true;
// Calculate and update the pivot table data
pt.CalculateData();
// Save the workbook
const outputFileName = 'UpdateDataSource_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the generated file from the VFS and trigger the download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Update Pivot Table Data Source</h1>
<button onClick={updateDataSource}>Start</button>
</div>
);
}
export default App;
After the data source is updated and refreshed, the corresponding summary results in the pivot table are updated synchronously.

Frequently Asked Questions
No summary data is displayed after creating a pivot table
Cause: The CalculateData method is not called after adding fields to the pivot table, or the data fields are not correctly added to the data area.
Solution: Call pt.CalculateData() to recalculate the pivot table after completing the field layout, and make sure the numeric fields are added to the data area through the DataFields.Add method.
The pivot table data does not change after adding a filter
Cause: The CalculateData method is not called to recalculate after adding a label or value filter, or the filter is added to the wrong field.
Solution: Call pt.CalculateData() to recalculate the pivot table, and confirm that you use a property such as pt.RowFields.get(0) to get the correct field before adding the filter.
The pivot table data does not change after updating the data source
Cause: The pivot table cache is not refreshed after modifying the data source, so the pivot table still retains the old data.
Solution: After modifying the data source, set pt.Cache.IsRefreshOnLoad to true and call pt.CalculateData(), so that the pivot table is recalculated based on the latest data source.
Get a Free License
If you want to remove the evaluation message from the result document or get rid of the feature limitations, please contact sales to get a 30-day temporary license.