React (60)
Children categories
When you need to compare several metrics across multiple dimensions at the same time, a radar chart is a very intuitive way to present them — each dimension is placed on an axis radiating out from the center, and the values on those axes are joined into a polygon, so the shape immediately shows where the strengths and weaknesses are. Spire.XLS for JavaScript provides a complete charting API that supports creating radar charts directly in the browser via WebAssembly, without requiring a backend service.
This article covers two core features:
For installation and project configuration, please refer to Integrating Spire.XLS for JavaScript in a React Project. The following examples assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Create a Radar Chart
You can add a radar chart to a worksheet with the sheet.Charts.Add() method. The steps are as follows:
- Load the Excel file that contains the data and get the first worksheet.
- Add a radar chart with
Charts.Add({ chartType: ExcelChartType.Radar }). - Set the
DataRangeproperty to specify the chart data range: the first row holds the series names, the first column holds the category names for each axis, and the remaining cells hold the values. - Set
SeriesDataFromRange = falseso that the data is not taken from a row/column layout. - Set the chart title, position, and legend position.
- Save the workbook with the
Workbook.SaveToFile()method.
Below is a complete code example that shows how to create a radar chart in React:
function App() {
const createRadarChart = 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 = 'RadarChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile(inputFileName);
// Get the first worksheet
let sheet = workbook.Worksheets.get(0);
// Add a radar chart
let chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.Radar });
// Set the chart data range
chart.DataRange = sheet.Range.get("A1:C5");
chart.SeriesDataFromRange = false;
// Set the chart position
chart.LeftColumn = 7;
chart.TopRow = 6;
chart.RightColumn = 16;
chart.BottomRow = 29;
// Set the chart title
chart.ChartTitle = "Product Sales by Region";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// Set the legend position
chart.Legend.Position = xlsModule.LegendPositionType.Corner;
// Save the workbook
const outputFileName = 'CreateRadarChart.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the converted 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>Create a Radar Chart</h1>
<button onClick={createRadarChart}>Start</button>
</div>
);
}
export default App;
After running, the effect of creating a radar chart:

Style the Radar Chart
After creating the radar chart, you can further improve its appearance by setting the chart area, plot area, and series line colors. The steps are as follows:
- Get the radar chart object that has been created.
- Set the
ChartArea.Fill.ForeColorproperty to set the chart background color. - Set the
PlotArea.Fill.ForeColorproperty to set the plot area background color. - Set the
Series[i].Format.LineProperties.Colorproperty to specify the line color of each series;Series.get(0)andSeries.get(1)correspond to the two series in the data range. - Save the workbook.
Below is a complete code example that shows how to style the radar chart:
function App() {
const styleRadarChart = 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 = 'RadarChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile(inputFileName);
// Get the first worksheet
let sheet = workbook.Worksheets.get(0);
// Add a radar chart
let chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.Radar });
// Set the chart data range
chart.DataRange = sheet.Range.get("A1:C5");
chart.SeriesDataFromRange = false;
// Set the chart position
chart.LeftColumn = 7;
chart.TopRow = 6;
chart.RightColumn = 16;
chart.BottomRow = 29;
// Set the chart title
chart.ChartTitle = "Product Sales by Region";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// Style the radar chart
// Set the chart area background color
chart.ChartArea.Fill.ForeColor = xlsModule.Color.get_LightCyan();
// Set the plot area background color
chart.PlotArea.Fill.ForeColor = xlsModule.Color.get_LightYellow();
// Set the color of the first series line
chart.Series.get(0).Format.LineProperties.Color = xlsModule.Color.get_Orange();
// Set the color of the second series line
chart.Series.get(1).Format.LineProperties.Color = xlsModule.Color.get_CornflowerBlue();
// Save the workbook
const outputFileName = 'StyledRadarChart.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the converted 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>Style the Radar Chart</h1>
<button onClick={styleRadarChart}>Start</button>
</div>
);
}
export default App;
After running, the effect of styling the radar chart:

Frequently Asked Questions
The radar chart does not change after setting a series color
Reason: A radar chart draws each series as a line, so setting a fill color with Series.get(i).Format.Fill has no effect.
Solution: Set the line color through Series.get(i).Format.LineProperties.Color, for example:
chart.Series.get(0).Format.LineProperties.Color = xlsModule.Color.get_Orange();
How do I adjust the legend position of a radar chart?
Reason: The legend is docked to the right of the chart by default, where it competes with the plot area for width — especially noticeable on a radar chart, which already takes up a lot of horizontal space.
Solution: Set the legend position with the chart.Legend.Position property. The available values are LegendPositionType.Bottom, Corner, Top, Right, Left, and NotDocked. For example, to move the legend to the top-right corner:
chart.Legend.Position = xlsModule.LegendPositionType.Corner;
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.
In data analysis scenarios, bubble charts help intuitively display multi-dimensional data relationships. Each data point in a bubble chart is defined by three values: X-axis value, Y-axis value, and bubble size. Spire.XLS for JavaScript provides rich charting APIs that support creating bubble charts directly in the browser via WebAssembly, without requiring a backend service.
This article covers two core features:
For installation and project configuration, please refer to Integrating Spire.XLS for JavaScript in a React Project. The following examples assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Create a Bubble Chart
A bubble chart can be added to a worksheet using the sheet.Charts.Add() method. The specific steps are as follows:
- Create a
Workbookobject and get the first worksheet. - Add a bubble chart via
Charts.Add(ExcelChartType.Bubble). - Set the
DataRangeproperty to specify the chart data area. - Set
SeriesDataFromRange = falseto indicate that data is not obtained from row/column layout. - Set
Series[0].Bubblesto specify the bubble size data range. - Set the chart title, position, and dimensions.
- Save the workbook via
Workbook.SaveToFile().
The following is a complete code example that demonstrates creating a bubble chart in React:
function App() {
const createBubbleChart = 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 = 'CreateBubbleChart.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile(inputFileName);
// Get the first worksheet
let sheet = workbook.Worksheets.get(0);
// Add a bubble chart
let chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.Bubble });
// Set the chart data range
chart.DataRange = sheet.Range.get("A1:C5");
chart.SeriesDataFromRange = false;
// Set the bubble sizes
chart.Series.get(0).Bubbles = sheet.Range.get("C2:C5");
// Set the chart position
chart.LeftColumn = 7;
chart.TopRow = 6;
chart.RightColumn = 16;
chart.BottomRow = 29;
// Set the chart title
chart.ChartTitle = "Bubble Chart";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// Save the workbook
const outputFileName = 'CreateBubbleChart.xlsx';
workbook.SaveToFile(outputFileName);
// Dispose resources
workbook.Dispose();
// Read the converted 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>Create Bubble Chart</h1>
<button onClick={createBubbleChart}>Start</button>
</div>
);
}
export default App;
After running the code, the effect of creating a bubble chart is as follows:

Style the Bubble Chart
After creating a bubble chart, you can enhance its appearance by setting the chart area, plot area, and series colors. The specific steps are as follows:
- Get the created bubble chart object.
- Set the
ChartArea.Fill.ForeColorproperty to set the chart background color. - Set the
PlotArea.Fill.ForeColorproperty to set the plot area background color. - Set the
Series[0].Format.Fill.ForeColorproperty to set the series color. - Set the
Series[0].HasDataLabelsproperty to enable data labels, and specify the label content throughDataPoints.DefaultDataPoint.DataLabels. - Save the workbook.
The following is a complete code example that demonstrates how to style a bubble chart:
function App() {
const styleBubbleChart = 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 = 'CreateBubbleChart.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile(inputFileName);
// Get the first worksheet
let sheet = workbook.Worksheets.get(0);
// Add a bubble chart
let chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.Bubble });
// Set the chart data range
chart.DataRange = sheet.Range.get("A1:C5");
chart.SeriesDataFromRange = false;
// Set the bubble sizes
chart.Series.get(0).Bubbles = sheet.Range.get("C2:C5");
// Set the chart position
chart.LeftColumn = 7;
chart.TopRow = 6;
chart.RightColumn = 16;
chart.BottomRow = 29;
// Set the chart title
chart.ChartTitle = "Bubble Chart";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// Style the bubble chart
// Set chart area background color
chart.ChartArea.Fill.ForeColor = xlsModule.Color.get_LightCyan();
// Set plot area background color
chart.PlotArea.Fill.ForeColor = xlsModule.Color.get_LightYellow();
// Set series color
chart.Series.get(0).Format.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
chart.Series.get(0).Format.Fill.ForeColor = xlsModule.Color.get_Orange();
// Enable and set data labels
chart.Series.get(0).HasDataLabels = true;
chart.Series.get(0).DataPoints.DefaultDataPoint.DataLabels.HasCategoryName = true;
chart.Series.get(0).DataPoints.DefaultDataPoint.DataLabels.HasValue = true;
// Save the workbook
const outputFileName = 'StyledBubbleChart.xlsx';
workbook.SaveToFile(outputFileName);
// Dispose resources
workbook.Dispose();
// Read the converted 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>Style Bubble Chart</h1>
<button onClick={styleBubbleChart}>Start</button>
</div>
);
}
export default App;
After running the code, the effect of styling the bubble chart is as follows:

Frequently Asked Questions
What do columns A, B, and C in DataRange represent?
Reason: Each data point in a bubble chart needs three values — an X-axis value, a Y-axis value, and a bubble size — and the three columns specified by DataRange correspond to them exactly.
Solution: Taking chart.DataRange = sheet.Range.get("A1:C5") as an example, column A serves as the category (X axis), column B as the Y-axis value, and column C is set as the bubble size through chart.Series.get(0).Bubbles = sheet.Range.get("C2:C5"). The order of these three columns cannot be swapped, or both the point positions and the bubble sizes will be wrong.
Why does the data range start at A1 instead of A2?
Reason: The first row of the data range is used as the series name.
Solution: Include the header row in DataRange. In the example, the "Sales" shown in the legend comes from cell B1, so the data range is written as A1:C5 rather than A2:C5.
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.
In data analysis scenarios, trendlines help you visually identify data trends and predict directions from Excel charts. Spire.XLS for JavaScript provides rich trendline APIs that allow you to add various types of trendlines to chart series directly in the browser via WebAssembly, without requiring a backend service.
This article covers two core features:
For installation and project configuration, please refer to Integrating Spire.XLS for JavaScript in a React Project. The following examples assume Spire.XLS is installed and the WebAssembly module has been initialized.
Add Trendline to Chart
You can add trendlines to any series in a chart through the chart.Series.get(i).TrendLines.Add() method. Spire.XLS for JavaScript supports 4 types of trendlines defined in the TrendLineType enumeration:
Linear— Linear trendline, suitable for data showing steady increase or decreaseExponential— Exponential trendline, suitable for scenarios where the growth or decline rate acceleratesLogarithmic— Logarithmic trendline, suitable for data that changes rapidly then stabilizesMoving_Average— Moving average trendline, suitable for smoothing data fluctuations
Specific steps:
- Create a
Workbookobject and get the first worksheet. - Get the chart that needs a trendline through
Worksheet.Charts.get(i). - Call
chart.Series.get(0).TrendLines.Add()with thetypeparameter specifying the trendline type. - Save the workbook through
Workbook.SaveToFile().
Below is a complete code example showing how to add four different types of trendlines to an Excel chart in React:
function App() {
const addTrendline = 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 = 'ChartTrendline_en.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 chart from the first worksheet
let chart = workbook.Worksheets.get(0).Charts.get(0);
// Add linear trendline
chart.ChartTitle = "Linear Trendline";
chart.Series.get(0).TrendLines.Add({ type: xlsModule.TrendLineType.Linear });
// Add exponential trendline
chart = workbook.Worksheets.get(0).Charts.get(0);
chart.ChartTitle = "Exponential Trendline";
chart.Series.get(0).TrendLines.Add({ type: xlsModule.TrendLineType.Exponential });
// Add logarithmic trendline
chart.ChartTitle = "Logarithmic Trendline";
chart.Series.get(0).TrendLines.Add({ type: xlsModule.TrendLineType.Logarithmic });
// Add moving average trendline
chart.ChartTitle = "Moving Average Trendline";
chart.Series.get(0).TrendLines.Add({ type: xlsModule.TrendLineType.Moving_Average });
// Save the document
const outputFileName = 'AddTrendline.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted 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>Add Trendline to Chart</h1>
<button onClick={addTrendline}>Start</button>
</div>
);
}
export default App;
After running the code, you get the effect of adding four different types of trendlines to a chart:

Extract Trendline Formula
You can obtain the mathematical formula of a trendline through the trendLine.Formula property, making it easy to display the trendline's analytical expression in reports.
Specific steps:
- Load the
AddTrendline.xlsxfile generated in Step 1, which contains four charts. - Use
Worksheet.Charts.get(i)to iterate through all four charts. - Read the
trendLine.Formulaproperty from each chart to obtain the formula string, then save all formulas to a text file.
Below is a complete code example showing how to extract trendline formulas in React:
function App() {
const extractTrendlineFormula = 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 AddTrendline.xlsx file generated in Step 1 into VFS
const inputFileName = 'AddTrendline.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
let sheet = workbook.Worksheets.get(0);
let result = "Extracted trendline formulas from four charts:\n\n";
// Iterate through all four charts and extract trendline formulas
for (let i = 0; i < 4; i++) {
let chart = sheet.Charts.get(i);
let trendLine = chart.Series.get(0).TrendLines.get(0);
// Moving average trendline has no mathematical formula
if (trendLine.Type === xlsModule.TrendLineType.Moving_Average) {
result += `Chart ${i + 1} (${chart.ChartTitle}): N/A (Moving Average)\n`;
} else {
let formula = trendLine.Formula;
result += `Chart ${i + 1} (${chart.ChartTitle}): ${formula}\n`;
}
}
// Release resources
workbook.Dispose();
// Save the formulas to a text file and trigger download
const outputFileName = 'ExtractTrendline.txt';
const blob = new Blob([result], { type: "text/plain;charset=utf-8" });
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>Extract Trendline Formula</h1>
<button onClick={extractTrendlineFormula}>Start</button>
</div>
);
}
export default App;
After running the code, you get the effect of extracting trendline formulas:

FAQ
How to delete an added trendline from a chart?
Cause: A trendline has already been added to the chart, but it needs to be removed or replaced.
Solution: Use the TrendLines.RemoveAt(index) method to remove a trendline at a specific index. Indexing starts from 0. For example, chart.Series.get(0).TrendLines.RemoveAt(0) removes the first trendline from the first series.
How to set forward/backward prediction periods for a trendline?
Cause: A trendline can not only fit existing data, but also predict future or past values based on the trend.
Solution: Use the trendLine.Forward and trendLine.Backward properties to set the number of prediction periods forward and backward respectively. For example, trendLine.Forward = 2 predicts two periods beyond the current data, while trendLine.Backward = 1 extrapolates one period before the data.
Get 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.
When creating flowcharts, relationship diagrams, or data annotations, inserting lines into an Excel worksheet is a common requirement. Spire.XLS for JavaScript provides rich line APIs for creating various line types (straight lines, curved lines, elbow connectors, etc.) and arrow-tipped connectors. All operations are performed directly in the browser based on WebAssembly, 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.
Insert Different Types of Lines
The sheet.Lines.AddLine() method inserts line shapes at a specified position. Using the LineShapeType enum, you can create various line types: straight lines (Line), curved lines (CurveLine), elbow connectors (ElbowLine), and inverted lines (LineInv). The appearance of lines can be customized through properties such as DashStyle (dash style), Color (color), and Weight (thickness).
The main steps are as follows:
- Create a
Workbookobject and get the first worksheet. - Call the
Worksheet.Lines.AddLine()method, passing position parameters andLineShapeTypeto specify the line type. - Customize line appearance through the
DashStyle,Color,Weight, andEndArrowHeadStyleproperties. - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to insert four different types of lines into Excel in React:
function App() {
const addLineShapes = 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 for text measurement and column auto-fit
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Add a straight line - solid, CadetBlue, weight 2, with arrow
let line1 = sheet.Lines.AddLine({ row: 10, column: 2, width: 200, height: 1, lineShapeType: xlsModule.LineShapeType.Line });
line1.DashStyle = xlsModule.ShapeDashLineStyleType.Solid;
line1.Color = xlsModule.Color.get_CadetBlue();
line1.Weight = 2;
line1.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
// Add a curved line - dotted, OrangeRed, weight 2
let line2 = sheet.Lines.AddLine({ row: 12, column: 2, width: 200, height: 1, lineShapeType: xlsModule.LineShapeType.CurveLine });
line2.DashStyle = xlsModule.ShapeDashLineStyleType.Dotted;
line2.Color = xlsModule.Color.get_OrangeRed();
line2.Weight = 2;
// Add an elbow connector - DashDotDot, Purple, weight 2
let line3 = sheet.Lines.AddLine({ row: 14, column: 2, width: 200, height: 1, lineShapeType: xlsModule.LineShapeType.ElbowLine });
line3.DashStyle = xlsModule.ShapeDashLineStyleType.DashDotDot;
line3.Color = xlsModule.Color.get_Purple();
line3.Weight = 2;
// Add an inverted line - Dashed, Green, weight 2
let line4 = sheet.Lines.AddLine({ row: 16, column: 2, width: 200, height: 1, lineShapeType: xlsModule.LineShapeType.LineInv });
line4.DashStyle = xlsModule.ShapeDashLineStyleType.Dashed;
line4.Color = xlsModule.Color.get_Green();
line4.Weight = 2;
// Save the workbook
const outputFileName = 'AddLineShapes.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the saved 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>Add Line Shapes</h1>
<button onClick={addLineShapes}>Start</button>
</div>
);
}
export default App;
Effect of inserting different line types:

Insert Arrow-Tipped Lines
The sheet.TypedLines.AddLine() method inserts arrow-tipped lines. Unlike Lines.AddLine(), TypedLines supports precise positioning using pixel coordinates or row/column coordinates, and supports setting different arrow head styles on both ends (beginning BeginArrowHeadStyle and end EndArrowHeadStyle).
The main steps are as follows:
- Create a
Workbookobject and get the first worksheet. - Call the
Worksheet.TypedLines.AddLine()method to create a line. - Set line position through the
Top,Left,Width, andHeightproperties (in pixels). - Set arrow styles on both ends through
BeginArrowHeadStyleandEndArrowHeadStyle. - Specify the line type through
LineShapeType(straight, elbow, curved, etc.). - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to insert six different types of arrow lines into Excel in React:
function App() {
const addArrowLines = 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 for text measurement and column auto-fit
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Add a double-arrow line - solid blue
let line = sheet.TypedLines.AddLine();
line.Top = 10;
line.Left = 20;
line.Width = 100;
line.Height = 0;
line.Color = xlsModule.Color.get_Blue();
line.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
line.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
// Add a single-arrow line - solid red
let line_1 = sheet.TypedLines.AddLine();
line_1.Top = 50;
line_1.Left = 30;
line_1.Width = 100;
line_1.Height = 100;
line_1.Color = xlsModule.Color.get_Red();
line_1.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineNoArrow;
line_1.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
// Add an elbow arrow connector
let line3 = sheet.TypedLines.AddLine();
line3.LineShapeType = xlsModule.LineShapeType.ElbowLine;
line3.Width = 30;
line3.Height = 50;
line3.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
line3.Top = 100;
line3.Left = 50;
// Add an elbow double-arrow connector
let line2 = sheet.TypedLines.AddLine();
line2.LineShapeType = xlsModule.LineShapeType.ElbowLine;
line2.Width = 50;
line2.Height = 50;
line2.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
line2.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
line2.Left = 120;
line2.Top = 100;
// Add a curved arrow connector
line3 = sheet.TypedLines.AddLine();
line3.LineShapeType = xlsModule.LineShapeType.CurveLine;
line3.Width = 30;
line3.Height = 50;
line3.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrowOpen;
line3.Top = 100;
line3.Left = 200;
// Add a curved double-arrow connector
line2 = sheet.TypedLines.AddLine();
line2.LineShapeType = xlsModule.LineShapeType.CurveLine;
line2.Width = 30;
line2.Height = 50;
line2.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrowOpen;
line2.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrowOpen;
line2.Left = 250;
line2.Top = 100;
// Save the workbook
const outputFileName = 'AddArrowLines.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the saved 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>Add Arrow Lines</h1>
<button onClick={addArrowLines}>Start</button>
</div>
);
}
export default App;
Effect of inserting arrow-tipped lines:

Frequently Asked Questions
How do I retrieve and modify existing lines in a worksheet?
Reason: An Excel file with existing lines was imported, but it's unclear how to read or modify them.
Solution: Traverse the sheet.Shapes collection to retrieve line shape objects, then modify their properties via the ILineShape interface. For example, sheet.Shapes.get(0) gets the first shape, and after confirming it's a line type, you can modify properties like color, dash style, etc.
How do I delete lines from an Excel worksheet?
Reason: Need to remove excess lines that were created or imported.
Solution: Use sheet.Shapes.Remove(index) to delete a line object at a specified index from the shapes collection, or iterate through the Shapes collection to delete them one by one based on name or type conditions.
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.
Create Exploded Pie and Doughnut Charts in Excel with JavaScript in React
2026-09-10 08:16:03 Written by liu taliaPie charts and doughnut charts are the most intuitive chart types for showing the proportion of each data item. An exploded pie chart or exploded doughnut chart pulls all the slices apart, which makes every part stand out more clearly. Spire.XLS for JavaScript completes this directly in the browser based on WebAssembly, managing input/output files through a virtual file system (VFS), with no backend service required.
This article introduces 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.
Create an Exploded Pie Chart
The slices of an exploded pie chart are separated from each other, which is suitable for highlighting the proportion of each data item. To create an exploded pie chart, follow these steps:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel file that contains the data. - Use the
Workbook.Worksheets.get()method to get the worksheet that contains the data. - Call the
Charts.Add()method to add a chart and set theChartTypetoExcelChartType.PieExploded. - Use the
Series.CategoryLabelsandSeries.Valuesproperties to specify the categories and values of the chart. - Set properties such as the chart title, position and data labels.
- Use the
Workbook.SaveToFile()method to save the workbook.
Here is a complete code example showing how to create an exploded pie chart from the product sales data in a worksheet in React:
function App() {
const createExplodedPieChart = 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 = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the worksheet that contains the data
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a chart and set its chart type to an exploded pie chart
const chart = sheet.Charts.Add();
chart.ChartType = xlsModule.ExcelChartType.PieExploded;
// Set the data range and the title of the chart
chart.DataRange = sheet.Range.get("B2:B7");
chart.SeriesDataFromRange = false;
chart.ChartTitle = "Product Sales Share";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// Set the category labels and the values of the chart, and show the value labels
const cs = chart.Series.get(0);
cs.CategoryLabels = sheet.Range.get("A2:A7");
cs.Values = sheet.Range.get("B2:B7");
cs.DataPoints.DefaultDataPoint.DataLabels.HasValue = true;
// Set the position of the chart
chart.LeftColumn = 4;
chart.TopRow = 1;
chart.RightColumn = 15;
chart.BottomRow = 25;
// Hide the background of the plot area and set the position of the legend
chart.PlotArea.Fill.Visible = false;
chart.Legend.Position = xlsModule.LegendPositionType.Right;
// Save the document
const outputFileName = 'ExplodedPieChart_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// 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>Create Exploded Pie Chart</h1>
<button onClick={createExplodedPieChart}>
Start
</button>
</div>
);
}
export default App;
After running the code, you can see the effect of the exploded pie chart:

Create an Exploded Doughnut Chart
A doughnut chart is similar to a pie chart, but it has a hole in the center and can also show the proportion of each part in the whole. An exploded doughnut chart further pulls the slices apart. To create an exploded doughnut chart, follow these steps:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel file that contains the data. - Use the
Workbook.Worksheets.get()method to get the worksheet that contains the data. - Call the
Charts.Add()method to add a chart and set theChartTypetoExcelChartType.DoughnutExploded. - Use the
Series.CategoryLabelsandSeries.Valuesproperties to specify the categories and values of the chart. - Set properties such as the chart title, position and data labels.
- Use the
Workbook.SaveToFile()method to save the workbook.
Here is a complete code example showing how to create an exploded doughnut chart from the product sales data in a worksheet in React:
function App() {
const createExplodedDoughnutChart = 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 = 'SalesData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the worksheet that contains the data
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a chart and set its chart type to an exploded doughnut chart
const chart = sheet.Charts.Add();
chart.ChartType = xlsModule.ExcelChartType.DoughnutExploded;
// Set the data range and the title of the chart
chart.DataRange = sheet.Range.get("B2:B7");
chart.SeriesDataFromRange = false;
chart.ChartTitle = "Sales Share by Product";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
// Set the category labels and the values of the chart, and show the value labels
const cs = chart.Series.get(0);
cs.CategoryLabels = sheet.Range.get("A2:A7");
cs.Values = sheet.Range.get("B2:B7");
cs.DataPoints.DefaultDataPoint.DataLabels.HasValue = true;
// Set the position of the chart
chart.LeftColumn = 4;
chart.TopRow = 1;
chart.RightColumn = 15;
chart.BottomRow = 25;
// Hide the background of the plot area and set the position of the legend
chart.PlotArea.Fill.Visible = false;
chart.Legend.Position = xlsModule.LegendPositionType.Right;
// Save the document
const outputFileName = 'ExplodedDoughnutChart_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// 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>Create Exploded Doughnut Chart</h1>
<button onClick={createExplodedDoughnutChart}>
Start
</button>
</div>
);
}
export default App;
After running the code, you can see the effect of the exploded doughnut chart:

FAQ
The created chart is blank with no slices
Cause: The chart has no valid data series. For example, the DataRange or Values points to an empty range or a range without numbers, so the chart has no data to draw.
Solution: Assign a data range that contains the data to the chart, for example:
chart.DataRange = sheet.Range.get("A1:B7");
const cs = chart.Series.get(0);
cs.CategoryLabels = sheet.Range.get("A2:A7");
cs.Values = sheet.Range.get("B2:B7");
Want to show percentages instead of values in the data labels
Cause: Pie and doughnut charts are usually used to show proportions, but the data labels show values by default, or the percentage labels are not enabled.
Solution: Disable the value labels and enable the percentage labels, for example:
const cs = chart.Series.get(0);
cs.DataPoints.DefaultDataPoint.DataLabels.HasValue = false;
cs.DataPoints.DefaultDataPoint.DataLabels.HasPercentage = true;
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.
Different Headers and Footers in Excel with JavaScript in React
2026-09-10 08:09:34 Written by liu taliaBy default, Excel displays the same header and footer at the top and bottom of every page. However, when printing formal reports, manuals, or theses, it is often necessary for different pages to show different headers and footers — for example, odd and even pages can use different headers, or the first page can have no header/footer while only the body pages show the page number. Spire.XLS for JavaScript completes this directly in the browser based on WebAssembly, managing input/output files through a virtual file system (VFS), with no backend service required.
This article introduces two core features:
- Set Different Headers and Footers for Odd and Even Pages
- Set a Different Header and Footer on the First Page
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 Different Headers and Footers for Odd and Even Pages
In books, papers or reports printed on both sides of the page, odd and even pages usually use different headers and footers, for example the header of odd pages shows the chapter name and the header of even pages shows the book title. To set different headers and footers for odd and even pages with Spire.XLS for JavaScript, follow these steps:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel file. - Use the
Workbook.Worksheets.get()method to get the specified worksheet. - Set the
PageSetup.DifferentOddEvenproperty to1to enable different headers and footers for odd and even pages. - Use the
PageSetup.OddHeaderStringandPageSetup.OddFooterStringproperties to set the header and footer of odd pages. - Use the
PageSetup.EvenHeaderStringandPageSetup.EvenFooterStringproperties to set the header and footer of even pages. - Use the
Workbook.SaveToFile()method to save the workbook.
Here is a complete code example showing how to set different headers and footers for the odd and even pages of a worksheet in React (the sample input file contains data that spans multiple pages, making it easy to observe the effect on different pages):
function App() {
const setOddEvenHeaderFooter = 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 = 'DifferentHeaderFooter.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);
// Enable different headers and footers for odd and even pages
sheet.PageSetup.DifferentOddEven = 1;
// Set the header and footer for odd pages (orange, bold)
sheet.PageSetup.OddHeaderString = "&\"Arial\"&12&B&KFFC000Odd Page Header";
sheet.PageSetup.OddFooterString = "&\"Arial\"&12&B&KFFC000Odd Page Footer";
// Set the header and footer for even pages (red, bold)
sheet.PageSetup.EvenHeaderString = "&\"Arial\"&12&B&KFF0000Even Page Header";
sheet.PageSetup.EvenFooterString = "&\"Arial\"&12&B&KFF0000Even Page Footer";
// Switch to Page Layout view to preview the header and footer
sheet.ViewMode = xlsModule.ViewMode.Layout;
// Save the document
const outputFileName = 'DifferentHeaderFooterOddEven_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 Different Header and Footer for Odd and Even Pages</h1>
<button onClick={setOddEvenHeaderFooter}>
Start
</button>
</div>
);
}
export default App;
After this setting, different headers and footers are applied to odd and even pages.

Set a Different Header and Footer on the First Page
Many formal documents require the first page (cover page) to display no header/footer or a dedicated header/footer, while the body pages display a header and footer carrying document information. In this case, you can enable "different first page" and set the header and footer of the first page separately. The steps are as follows:
- Create a
Workbookobject and use theLoadFromFile()method to load the Excel file. - Use the
Workbook.Worksheets.get()method to get the specified worksheet. - Set the
PageSetup.DifferentFirstproperty to1to enable a header and footer on the first page that differ from those on the other pages. - Use the
PageSetup.FirstHeaderStringandPageSetup.FirstFooterStringproperties to set the header and footer of the first page. - Use properties such as
PageSetup.LeftHeaderandPageSetup.CenterFooterto set the header and footer of the other pages. - Use the
Workbook.SaveToFile()method to save the workbook.
Here is a complete code example showing how to set a different header and footer on the first page of a worksheet in React:
function App() {
const setFirstPageHeaderFooter = 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 = 'DifferentHeaderFooter.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);
// Enable a different header and footer on the first page
sheet.PageSetup.DifferentFirst = 1;
// Set the header and footer for the first page (blue, bold)
sheet.PageSetup.FirstHeaderString = "&\"Arial\"&16&B&K4253E2First Page Header";
sheet.PageSetup.FirstFooterString = "&\"Arial\"&16&B&K4253E2First Page Footer";
// Set the header and footer for the other pages (gray, bold)
sheet.PageSetup.LeftHeader = "&\"Arial\"&12&B&K808080Other Pages Header";
sheet.PageSetup.CenterFooter = "&\"Arial\"&12&B&K808080Other Pages Footer";
// Switch to Page Layout view to preview the header and footer
sheet.ViewMode = xlsModule.ViewMode.Layout;
// Save the document
const outputFileName = 'DifferentHeaderFooterFirstPage_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 Different Header and Footer on the First Page</h1>
<button onClick={setFirstPageHeaderFooter}>
Start
</button>
</div>
);
}
export default App;
After this setting, the first page uses a different header and footer from the other pages.

FAQ
The header and footer on the first page is not applied
Cause: The "different first page" option was not enabled. If only FirstHeaderString/FirstFooterString are set without setting PageSetup.DifferentFirst to 1, Excel ignores the first-page header and footer.
Solution: Enable sheet.PageSetup.DifferentFirst = 1; before setting the header and footer of the first page.
Header/footer text shows as garbled characters or boxes
Cause: Browser-side Excel processing depends on font files. If the font used by the text (such as ARIAL.TTF) has not been loaded into the virtual file system (VFS), the text may not render correctly.
Solution: Load the font into the VFS with FetchFileToVFS() before calling Workbook.LoadFromFile(), for example:
await window.spire.FetchFileToVFS(
'ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`
);
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.
Create and Remove Multi-level Groups in Excel with JavaScript in React
2026-09-10 02:39:45 Written by Nina TangWhen managing data with many rows and columns, such as project plans or financial reports, you often need to group some rows (Group / Outline) so that they can be collapsed into a layered structure, letting you view only the summary rows or the content of a certain phase. When the structure is no longer needed, you can remove the groups at any time to restore the flat layout of the rows. Spire.XLS for JavaScript completes this 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.
Create Multi-level (Nested) Groups
A multi-level group consists of an "outer group" plus "inner groups". For example, in a project plan, the whole execution phase (several rows) can be one level of group, while the detail rows of each sub-phase are the second level of group. When creating it, you should call GroupByRows() on the larger outer range first, and then on the smaller inner ranges, so that Excel generates the collapse buttons of different levels. The main steps are as follows:
- Create a
Workbookobject and get the first worksheet. - Add a named style and set its font (used for titles and similar cells).
- Set
Worksheet.PageSetup.IsSummaryRowBelow = falseso that the summary rows are shown above the detail rows. - Write the sample data into the cells.
- Call
GroupByRows()on the outer row range (rows 2-9) first, then callGroupByRows()on the nested inner row ranges (rows 4-5 and rows 8-9). - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to create two-level (nested) row groups for a worksheet in React:
function App() {
const createNestedGroup = 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 for text measurement
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Add a named style for the title rows
const style = workbook.Styles.Add("style");
style.Font.Color = xlsModule.Color.get_CadetBlue();
style.Font.IsBold = true;
// Make the summary rows appear above the detail rows
sheet.PageSetup.IsSummaryRowBelow = false;
// Write the sample data
sheet.Range.get("A1").Value = "Project plan for project X";
sheet.Range.get("A1").CellStyleName = style.Name;
sheet.Range.get("A3").Value = "Set up";
sheet.Range.get("A3").CellStyleName = style.Name;
sheet.Range.get("A4").Value = "Task 1";
sheet.Range.get("A5").Value = "Task 2";
sheet.Range.get("A4:A5").BorderAround(xlsModule.LineStyleType.Thin);
sheet.Range.get("A4:A5").BorderInside(xlsModule.LineStyleType.Thin);
sheet.Range.get("A7").Value = "Launch";
sheet.Range.get("A7").CellStyleName = style.Name;
sheet.Range.get("A8").Value = "Task 1";
sheet.Range.get("A9").Value = "Task 2";
sheet.Range.get("A8:A9").BorderAround(xlsModule.LineStyleType.Thin);
sheet.Range.get("A8:A9").BorderInside(xlsModule.LineStyleType.Thin);
// Group the outer rows first, then the nested inner rows, to form multi-level groups
sheet.GroupByRows(2, 9, false);
sheet.GroupByRows(4, 5, false);
sheet.GroupByRows(8, 9, false);
// Save the document
const outputFileName = 'MultiLevelGroup.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>Create Nested Group</h1>
<button onClick={createNestedGroup}>
Start
</button>
</div>
);
}
export default App;
Effect of creating multi-level groups

Remove (Delete) Multi-level Groups
When a workbook already contains multi-level groups and you need to remove a particular outer "large group" or inner "small group", you can load the file and call the Worksheet.UngroupByRows() method on the corresponding range. Grouping only affects the collapsed display of rows; removing a group never deletes any cell content. After the outer large group is removed, the inner small groups that were nested inside it remain as independent single-level groups and can be removed one by one. The main steps are as follows:
- Create a
Workbookobject and load the workbook that already contains multi-level groups with theWorkbook.LoadFromFile()method. - Get the worksheet with the
Workbook.Worksheets.get()method. - Call
UngroupByRows()on the outer row range (rows 2-9) to remove the large group. - Call
UngroupByRows()on the inner row range (rows 4-5) to remove the small group. - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to load an already-grouped Excel file in React and remove a large group and a small group:
function App() {
const ungroupRows = 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 for text measurement
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file that already contains multi-level groups
const inputFileName = 'MultiLevelGroup.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Create a Workbook object and load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet
const sheet = workbook.Worksheets.get(0);
// Remove the outer large group (rows 2-9)
sheet.UngroupByRows(2, 9);
// Remove the inner small group (rows 4-5)
sheet.UngroupByRows(4, 5);
// Save the document
const outputFileName = 'UngroupRows_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</h1>
<button onClick={ungroupRows}>
Start
</button>
</div>
);
}
export default App;
Effect of removing multi-level groups

FAQ
Why does calling GroupByRows several times not produce multi-level groups
Cause: A multi-level group requires the range of the inner group to be completely contained within the range of the outer group. If two grouped ranges do not contain each other, Excel treats them as two groups of the same level instead of nested multi-level groups.
Solution: Call GroupByRows() on the larger outer range first, and then on the smaller inner range, for example call GroupByRows(2, 9, false) first and then GroupByRows(4, 5, false).
How can I make a group collapsed by default (or keep it expanded)?
Cause: The third Boolean parameter of GroupByRows(startRow, endRow, isCollapsed) decides whether the detail rows of a group are collapsed by default after the group is created. true collapses them by default, while false keeps them expanded (the examples in this article use false). When the saved file is opened, it is shown in that state.
Solution: Set the third parameter to true to collapse the group by default, for example sheet.GroupByRows(4, 5, true). To collapse or expand a group at runtime, call CollapseGroup() / ExpandGroup() on the grouped range.
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.
Add, Read, Modify, and Delete Excel Hyperlinks with JavaScript in React
2026-09-09 08:58:49 Written by Nina TangHyperlinks are a common element in Excel for quickly jumping to web pages, email addresses, or other resources, and they often appear in tables such as product websites, contact information, and reference materials. Spire.XLS for JavaScript uses WebAssembly to add, read, modify, and delete hyperlinks directly in the browser and manages input/output files through a virtual file system (VFS) without any backend support.
This article demonstrates the following common features:
For installation and project configuration, please refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume that Spire.XLS is installed and the WebAssembly module has been initialized.
Add a Hyperlink to Text
For cells that contain text such as company names, website names, or email addresses, you can add hyperlinks to the text so that users can click to jump to a web page or send an email.
function App() {
const addHyperlinkToText = 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 the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'HyperlinksSample.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 web hyperlink to the text in cell D10
const urlLink = sheet.HyperLinks.Add({ range: sheet.Range.get('D10') });
urlLink.TextToDisplay = sheet.Range.get('D10').Text;
urlLink.Type = xlsModule.HyperLinkType.Url;
urlLink.Address = 'https://www.e-iceblue.com/';
// Add an email hyperlink to the text in cell E10
const mailLink = sheet.HyperLinks.Add({ range: sheet.Range.get('E10') });
mailLink.TextToDisplay = sheet.Range.get('E10').Text;
mailLink.Type = xlsModule.HyperLinkType.Url;
mailLink.Address = 'mailto:support@e-iceblue.com';
// Save the workbook
const outputFileName = 'AddHyperlinkToText_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook
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>Add Hyperlink To Text</h1>
<button onClick={addHyperlinkToText}>Start</button>
</div>
);
}
export default App;
After running, the text in cell D10 becomes a clickable web link, and the email address in cell E10 becomes an email link that can be used to send an email.

Read Hyperlinks
Through the Worksheet.HyperLinks collection, you can get all the hyperlinks in a worksheet and access the target address of each hyperlink by index.
function App() {
const readHyperlinks = 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 Excel file into the VFS
const inputFileName = 'HyperlinksSample.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);
// Read the target addresses of all hyperlinks
const hyperlinkCount = sheet.HyperLinks.Count;
let allAddresses = '';
for (let i = 0; i < hyperlinkCount; i++) {
const address = sheet.HyperLinks.get(i).Address;
allAddresses += address + '\n';
}
// Save the hyperlink addresses as a txt file
const outputFileName = 'ReadHyperlinks_output.txt';
window.dotnetRuntime.Module.FS.writeFile(outputFileName, allAddresses);
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: '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 Hyperlinks</h1>
<button onClick={readHyperlinks}>Start</button>
</div>
);
}
export default App;
Use the HyperLinks.Count property to get the total number of hyperlinks in the worksheet.

Modify a Hyperlink
After getting a hyperlink by index with HyperLinks.get(0), you can reset its display text and target address to modify the hyperlink.
function App() {
const modifyHyperlink = 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 the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'HyperlinksSample.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 all hyperlinks in the worksheet
const links = sheet.HyperLinks;
// Modify the display text and target address of the first hyperlink
links.get(0).TextToDisplay = 'E-iceblue';
links.get(0).Address = 'https://www.e-iceblue.com/';
// Save the workbook
const outputFileName = 'ModifyHyperlink_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook
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>Modify Hyperlink</h1>
<button onClick={modifyHyperlink}>Start</button>
</div>
);
}
export default App;
After modification, both the display text and the target address of the first hyperlink are updated.

Remove Hyperlinks
Use the HyperLinks.RemoveAt(index) method to only remove the hyperlink and keep the text, or use the Range.ClearAll() method to clear all content in the cell, including the hyperlink.
function App() {
const removeHyperlinks = 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 the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'HyperlinksSample.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 all hyperlinks in the worksheet
const links = sheet.HyperLinks;
// Clear all content in the linked cells
// sheet.Range.get('A1').ClearAll();
// sheet.Range.get('A2').ClearAll();
// sheet.Range.get('A3').ClearAll();
// Only remove the hyperlink and keep the original text
sheet.HyperLinks.RemoveAt(0);
// Save the workbook
const outputFileName = 'RemoveHyperlinks_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook
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>Remove Hyperlinks</h1>
<button onClick={removeHyperlinks}>Start</button>
</div>
);
}
export default App;

Frequently Asked Questions
The target address is not updated after modifying the hyperlink
Reason: The wrong hyperlink index was modified, or there is no hyperlink on the target cell.
Solution: Make sure a hyperlink already exists in the worksheet, access it at the correct index such as sheet.HyperLinks.get(0), and then set its Address property.
Get a Free License
If you want to remove the evaluation message from the result documents or get rid of feature limitations, please contact sales to obtain a temporary license valid for 30 days.
When organizing data such as sales records or statistical reports, converting a plain data range into an Excel table (Table / ListObject) gives the data a dedicated header row, automatic filter drop-downs, banded styling, and a "total row", which makes later browsing and summarizing more convenient. After the table is created, its appearance can also be adjusted at any time through built-in styles and various display options. Spire.XLS for JavaScript completes all of these operations 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.
Create a Table in Excel
Converting a data range into a table is a quick way to obtain a structured range that has built-in filter buttons and banded styling. In this example, a sales detail list (Product, Region, Month, Quantity, Sales Amount) is first written into the worksheet, then the A1:E13 range is converted into a table named "Table1" with ListObjects.Create(), and finally the built-in light style TableStyleLight9 is applied. The main steps are as follows:
- Create a
Workbookobject and get the first worksheet. - Write the headers and the sample data into the cells.
- Call the
Worksheet.ListObjects.Create()method to convert the range that contains the headers into a table. - Apply a built-in style to the table through the
IListObject.BuiltInTableStyleproperty. - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to create an Excel table for a worksheet in React:
function App() {
const createTable = 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 for text measurement and column auto-fit
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Write the headers
sheet.Range.get('A1').Value = 'Product';
sheet.Range.get('B1').Value = 'Region';
sheet.Range.get('C1').Value = 'Month';
sheet.Range.get('D1').Value = 'Quantity';
sheet.Range.get('E1').Value = 'Sales Amount';
// Write the sample data
sheet.Range.get('A2').Value = 'Laptop';
sheet.Range.get('B2').Value = 'North';
sheet.Range.get('C2').Value = 'Jan';
sheet.Range.get('D2').NumberValue = 120;
sheet.Range.get('E2').NumberValue = 239760;
sheet.Range.get('A3').Value = 'Monitor';
sheet.Range.get('B3').Value = 'East';
sheet.Range.get('C3').Value = 'Jan';
sheet.Range.get('D3').NumberValue = 80;
sheet.Range.get('E3').NumberValue = 103920;
sheet.Range.get('A4').Value = 'Keyboard';
sheet.Range.get('B4').Value = 'South';
sheet.Range.get('C4').Value = 'Jan';
sheet.Range.get('D4').NumberValue = 200;
sheet.Range.get('E4').NumberValue = 59800;
sheet.Range.get('A5').Value = 'Laptop';
sheet.Range.get('B5').Value = 'East';
sheet.Range.get('C5').Value = 'Feb';
sheet.Range.get('D5').NumberValue = 150;
sheet.Range.get('E5').NumberValue = 299700;
sheet.Range.get('A6').Value = 'Mouse';
sheet.Range.get('B6').Value = 'North';
sheet.Range.get('C6').Value = 'Feb';
sheet.Range.get('D6').NumberValue = 300;
sheet.Range.get('E6').NumberValue = 26700;
sheet.Range.get('A7').Value = 'Printer';
sheet.Range.get('B7').Value = 'South';
sheet.Range.get('C7').Value = 'Feb';
sheet.Range.get('D7').NumberValue = 60;
sheet.Range.get('E7').NumberValue = 65940;
sheet.Range.get('A8').Value = 'Monitor';
sheet.Range.get('B8').Value = 'West';
sheet.Range.get('C8').Value = 'Feb';
sheet.Range.get('D8').NumberValue = 90;
sheet.Range.get('E8').NumberValue = 116910;
sheet.Range.get('A9').Value = 'Keyboard';
sheet.Range.get('B9').Value = 'North';
sheet.Range.get('C9').Value = 'Mar';
sheet.Range.get('D9').NumberValue = 180;
sheet.Range.get('E9').NumberValue = 53820;
sheet.Range.get('A10').Value = 'Router';
sheet.Range.get('B10').Value = 'East';
sheet.Range.get('C10').Value = 'Mar';
sheet.Range.get('D10').NumberValue = 70;
sheet.Range.get('E10').NumberValue = 27930;
sheet.Range.get('A11').Value = 'Laptop';
sheet.Range.get('B11').Value = 'West';
sheet.Range.get('C11').Value = 'Mar';
sheet.Range.get('D11').NumberValue = 140;
sheet.Range.get('E11').NumberValue = 279860;
sheet.Range.get('A12').Value = 'Printer';
sheet.Range.get('B12').Value = 'North';
sheet.Range.get('C12').Value = 'Apr';
sheet.Range.get('D12').NumberValue = 110;
sheet.Range.get('E12').NumberValue = 120890;
sheet.Range.get('A13').Value = 'Mouse';
sheet.Range.get('B13').Value = 'South';
sheet.Range.get('C13').Value = 'Apr';
sheet.Range.get('D13').NumberValue = 260;
sheet.Range.get('E13').NumberValue = 23140;
// Convert the A1:E13 data range into an Excel table (ListObject)
const table = sheet.ListObjects.Create('Table1', sheet.Range.get({ row: 1, column: 1, lastRow: 13, lastColumn: 5 }));
// Apply a built-in light table style
table.BuiltInTableStyle = xlsModule.TableBuiltInStyles.TableStyleLight9;
// Auto-fit the columns so that the contents are fully shown
sheet.AllocatedRange.AutoFitColumns();
// Save the workbook
const outputFileName = 'CreateTable.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the saved 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 Table</h1>
<button onClick={createTable}>Start</button>
</div>
);
}
export default App;
Effect of creating the table:

Set the Table Style, Total Row and Stripes
A created table can be restyled at any time: for example, replace the light style with the built-in Medium dark style, show a total row at the bottom of the table and let the "Quantity" and "Sales Amount" columns be summed automatically, and enable both row and column stripes to make the data easier to read. The main steps are as follows:
- Create a
Workbookobject and load a workbook that already contains a table with theWorkbook.LoadFromFile()method. - Get the worksheet with the
Workbook.Worksheets.get()method, and then get the table object withListObjects.get(). - Assign a new built-in style through the
BuiltInTableStyleproperty. - Set
DisplayTotalRowtotrueto show the total row, and useColumns[].TotalsRowLabelandColumns[].TotalsCalculationto set the label and the calculation of the total row columns. - Enable row and column stripes with
ShowTableStyleRowStripesandShowTableStyleColumnStripes. - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to load a created table in React and set its style and total row:
function App() {
const formatTable = 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 for text measurement and column auto-fit
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file created in the previous section, which already contains a table
const inputFileName = 'CreateTable.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Create a Workbook object and load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Get the first worksheet and the table in it
const sheet = workbook.Worksheets.get(0);
const table = sheet.ListObjects.get(0);
// Apply a built-in Medium table style
table.BuiltInTableStyle = xlsModule.TableBuiltInStyles.TableStyleMedium9;
// Show the total row
table.DisplayTotalRow = true;
// Set the label of the first column of the total row to "Total"
table.Columns.get(0).TotalsRowLabel = 'Total';
// Do not calculate the text columns, and sum the "Quantity" and "Sales Amount" columns automatically
table.Columns.get(1).TotalsCalculation = xlsModule.ExcelTotalsCalculation.None;
table.Columns.get(2).TotalsCalculation = xlsModule.ExcelTotalsCalculation.None;
table.Columns.get(3).TotalsCalculation = xlsModule.ExcelTotalsCalculation.Sum;
table.Columns.get(4).TotalsCalculation = xlsModule.ExcelTotalsCalculation.Sum;
// Show the row stripes and column stripes
table.ShowTableStyleRowStripes = true;
table.ShowTableStyleColumnStripes = true;
// Auto-fit the columns so that the contents are fully shown
sheet.AllocatedRange.AutoFitColumns();
// Save the workbook
const outputFileName = 'FormatTable_out.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the saved 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>Format Table</h1>
<button onClick={formatTable}>Start</button>
</div>
);
}
export default App;
Effect of setting the table style:

Frequently Asked Questions
How do I change the built-in style of a table? What styles are available?
Reason: The BuiltInTableStyle property was not reassigned after the table was created, or the wrong enum type was assigned to the property.
Solution: Reassign the IListObject.BuiltInTableStyle property. Its values come from the TableBuiltInStyles enum, which provides multiple built-in styles including Light (TableStyleLight1 ~ TableStyleLight21), Medium (TableStyleMedium1 ~ TableStyleMedium28) and Dark (TableStyleDark1 ~ TableStyleDark11). For example, this article first applies TableStyleLight9 and then switches to TableStyleMedium9.
How do I name a table or rename it? What happens if two tables have the same name?
Reason: The first parameter of ListObjects.Create() is the table name, e.g. Create("Table1", ...). Within the same worksheet, table names must be unique; otherwise creating another table with the same name raises an error.
Solution: Pass a unique name when creating the table (e.g. "SalesTable1"). To rename an existing table, set its DisplayName property directly, for example table.DisplayName = "SalesTable2025";.
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.
Accept or Reject Tracked Changes in Excel with JavaScript in React
2026-09-09 08:12:04 Written by liu taliaWhen multiple users collaborate on an Excel document with tracking changes (Track Changes) enabled, every insertion, modification and deletion made to cells is recorded. When reviewing these changes, you often need to accept all tracked changes (to formally merge the changes of others into the document) or reject all tracked changes (to revert all changes and restore the state before the edits). Handling these changes one by one in Excel is tedious and error-prone, while processing them in bulk through code in a web application is far more efficient. Spire.XLS for JavaScript completes this directly in the browser based on WebAssembly, and manages input/output files through a virtual file system (VFS), with no backend service required.
Spire.XLS for JavaScript provides revision-handling capabilities through the workbook object: after loading a workbook that contains revision records, call the AcceptAllTrackedChanges() method to accept all tracked changes in the document, or call the RejectAllTrackedChanges() method to reject all tracked changes in the document.
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.
Accept All Tracked Changes in Excel
When a workbook containing revision records has been edited by multiple users and passes review, all the changes need to be formally merged into the document, that is, the tracked changes are "accepted". After the changes are accepted, they become the official content of the document and the revision records are cleared. The main steps are as follows:
- Create a
Workbookobject. - Load the workbook containing revision records with the
Workbook.LoadFromFile()method. - Call the
Workbook.AcceptAllTrackedChanges()method to accept all tracked changes in the document. - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to accept all tracked changes in an Excel workbook in React:
function App() {
const acceptTrackedChanges = 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 the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'TrackChanges.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Create a Workbook object and load the workbook containing tracked changes
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Accept all tracked changes in the document
workbook.AcceptAllTrackedChanges();
// Save the document
const outputFileName = 'AcceptTrackedChanges_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>Accept All Tracked Changes</h1>
<button onClick={acceptTrackedChanges}>
Start
</button>
</div>
);
}
export default App;
Effect of accepting all tracked changes

Reject All Tracked Changes in Excel
When the tracked changes are disputed or no longer needed, the reviewer can reject all of them at once so that the document returns to the state before the edits. The main steps are as follows:
- Create a
Workbookobject. - Load the workbook containing revision records with the
Workbook.LoadFromFile()method. - Call the
Workbook.RejectAllTrackedChanges()method to reject all tracked changes in the document. - Save the workbook with the
Workbook.SaveToFile()method.
Here is a complete code example showing how to reject all tracked changes in an Excel workbook in React:
function App() {
const rejectTrackedChanges = 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 the Excel file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'TrackChanges.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Create a Workbook object and load the workbook containing tracked changes
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
// Reject all tracked changes in the document
workbook.RejectAllTrackedChanges();
// Save the document
const outputFileName = 'RejectTrackedChanges_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>Reject All Tracked Changes</h1>
<button onClick={rejectTrackedChanges}>
Start
</button>
</div>
);
}
export default App;
Effect of rejecting all tracked changes

FAQ
The content is not restored to its pre-edit state after rejecting tracked changes
Cause: RejectAllTrackedChanges() rejects only the cell changes that were recorded by the Track Changes feature. If some changes were made before tracking was enabled, or were written by other means and never recorded, they are not revisions that can be rejected, so they keep their current values and the document will not fully return to the original baseline.
Can I accept or reject only part of the tracked changes instead of all of them
Cause: AcceptAllTrackedChanges() and RejectAllTrackedChanges() process all the revisions of a whole workbook at once. They do not provide APIs for filtering individual revisions by user, time or cell range.
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.