Spire.XLS for JavaScript (86)
Children categories
The most direct way to get data into Excel is to assign one cell at a time, which means ten rows take ten loop iterations. But data usually arrives in JavaScript already in blocks -- a list from an API, a table rendered on the page, a computed result set -- and there is no reason to break an array apart just to feed it back cell by cell. The InsertArray method of Spire.XLS for JavaScript takes a whole array at once; combined with a starting row and column and a write direction, a single call drops an entire column or row of data into the worksheet. Spire.XLS for JavaScript performs these operations directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two core feature points:
- Import a one-dimensional array into a worksheet
- Import a two-dimensional data table into a worksheet
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialized.
Import a one-dimensional array into a worksheet
InsertArray is split into several overloads by data type: stringArray for text, intArray for integers and doubleArray for decimals. That split is not needless fussiness -- Excel treats cells according to their data type. Numbers sit right-aligned and can take part in sums and charts directly, while a number written as text sits left-aligned and a formula referencing it only yields 0. Scores, amounts and quantities -- anything that will be used in a calculation -- belong in a numeric overload.
The remaining parameters decide where the data lands: firstRow and firstColumn give the starting position, with rows and columns both counted from 1, and isVertical picks the direction the array spreads -- false lays it along a row, true down a column. The same ['Jan', 'Feb', 'Mar'] becomes either a header row spanning A1 to C1 or a column of data running down A1 to A3. The steps are:
- Load the font into the VFS.
- Create a
Workbookand get the first worksheet withWorksheets.get(0). - Write a header row horizontally with the
stringArrayoverload ofInsertArray. - Write the name column vertically with
stringArrayand the score column withintArray. - Auto-fit the columns with
AllocatedRange.AutoFitColumns, then save the workbook withSaveToFile.
The complete code example below shows how to import a one-dimensional array into a worksheet in React:
function App() {
const importArray = 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 and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Write a header row horizontally: isVertical false spreads the array across A1:B1
sheet.InsertArray({
stringArray: ['Name', 'Score'],
firstRow: 1,
firstColumn: 1,
isVertical: false,
});
// Write the name column vertically: isVertical true spreads the array down A2:A4
sheet.InsertArray({
stringArray: ['Alice', 'Bob', 'Carol'],
firstRow: 2,
firstColumn: 1,
isVertical: true,
});
// Write the score column: numbers go through the intArray overload, so the cells hold
// numbers rather than text
sheet.InsertArray({
intArray: [92, 85, 78],
firstRow: 2,
firstColumn: 2,
isVertical: true,
});
// Auto-fit the columns to their content
sheet.AllocatedRange.AutoFitColumns();
// Save the workbook
const outputFileName = 'ImportArray.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to release resources
workbook.Dispose();
// Read the result 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>Import 1-D Array</h1>
<button onClick={importArray}>Start</button>
</div>
);
}
export default App;
After running, the effect of importing a one-dimensional array into a worksheet:

Import a two-dimensional data table into a worksheet
A data table is naturally a two-dimensional array -- a header row first, then one record per row, as in [['Name', 'Subject', 'Score'], ['Alice', 'Math', 92]]. Importing a two-dimensional data table into Excel means splitting it by column and writing each column as a one-dimensional array on its own: write the header across one row, then write the body column by column, text columns with stringArray and numeric ones with intArray. A column holds a single data type throughout, so each call only has to pick one form. When the data arrives in batches, read LastRow to find the last row currently in use and write the next batch from the row after it. The steps are:
- Load the font into the VFS.
- Create a
Workbookand get the first worksheet withWorksheets.get(0). - Write the header across the first row with the
stringArrayoverload ofInsertArray. - Split the body by column and write each one vertically with
stringArrayorintArray. - When a second batch arrives, locate its starting row with
LastRowand write the columns the same way. - Auto-fit the columns with
AllocatedRange.AutoFitColumns, then save the workbook withSaveToFile.
The complete code example below shows how to import a two-dimensional data table into a worksheet in React:
function App() {
const importDataTable = 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/`);
// The two-dimensional data to import, with the header as its first row
const rows = [
['Name', 'Subject', 'Score'],
['Alice', 'Math', 92],
['Bob', 'Chinese', 85],
];
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Write one column: text columns go through stringArray, numeric ones through intArray
const writeColumn = (values, firstRow, firstColumn) => {
const isNumeric = values.every((value) => typeof value === 'number');
if (isNumeric) {
sheet.InsertArray({ intArray: values, firstRow, firstColumn, isVertical: true });
} else {
sheet.InsertArray({ stringArray: values, firstRow, firstColumn, isVertical: true });
}
};
// Write the header across the first row
sheet.InsertArray({
stringArray: rows[0],
firstRow: 1,
firstColumn: 1,
isVertical: false,
});
// Split the body by column and write each one vertically, starting at row 2
const body = rows.slice(1);
for (let column = 0; column < rows[0].length; column++) {
writeColumn(body.map((row) => row[column]), 2, column + 1);
}
// A second batch arrives: use LastRow to find where the existing data ends
const nextBatch = [
['Carol', 'English', 78],
['Dave', 'Physics', 91],
];
const startRow = sheet.LastRow + 1;
for (let column = 0; column < rows[0].length; column++) {
writeColumn(nextBatch.map((row) => row[column]), startRow, column + 1);
}
// Auto-fit the columns to their content
sheet.AllocatedRange.AutoFitColumns();
// Save the workbook
const outputFileName = 'ImportDataTable.xlsx';
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to release resources
workbook.Dispose();
// Read the result 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>Import 2-D Data Table</h1>
<button onClick={importDataTable}>Start</button>
</div>
);
}
export default App;
After running, the effect of importing a two-dimensional data table into a worksheet:

FAQ
How do I put a date into a cell?
Cause: dateTimeArray cannot be used to write a JavaScript Date -- it lands as 0001/1/1. Assigning cell by cell through Range.DateTimeValue does work, but it only accepts a Date object; hand it a string and it reports Value is not a Date.
Solution: For a whole column, the least fuss is to write the date as a yyyy-mm-dd string and pass it to stringArray. The saved cell holds a real date value -- reading NumberValue back gives the date serial number, such as 46037 -- and no number format has to be set:
sheet.InsertArray({
stringArray: ['2026-01-15', '2026-02-20'],
firstRow: 1,
firstColumn: 1,
isVertical: true,
});
When only one cell needs setting, assign it directly instead, taking care to pass a Date object rather than a string:
sheet.Range.get('A1').DateTimeValue = new Date(Date.UTC(2026, 0, 15));
Do empty values in the array break the write?
Cause: No. null, undefined and the empty string all write an empty cell. InsertArray places each value by its index, so what the value happens to be makes no difference: later elements do not shift, and nothing throws.
Solution: Nothing extra is needed; pass the array as it is. The line below fills A1:D1, with D still landing in the fourth column:
sheet.InsertArray({
stringArray: ['A', null, '', 'D'],
firstRow: 1,
firstColumn: 1,
isVertical: false,
});
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.
A chart plots averages, and an average says nothing about how steady the underlying readings were. The same rising line can sit on top of six near-identical measurements or six wildly scattered ones -- the curve alone will not tell you which. Error bars supply that missing layer: a short segment drawn at each data point marks the spread or uncertainty around it, so the reader can see how much confidence each turn of the line deserves. Percentage error bars derive their range from a fixed proportion of the value, while standard error bars derive theirs from the data itself, and the two suit different situations. Spire.XLS for JavaScript performs both directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialised.
Add percentage error bars to a line chart
A percentage error bar takes the value of each data point as its base and works out the range from the given percentage. Set it to 10, and a point valued at 4.0 gets an error amount of 0.4; which side of the data point that length is drawn on is decided by a separate parameter. This kind of error bar expresses a tolerance -- a production target allowed to drift by a tenth, or an instrument reading with a fixed relative precision. Error bars belong to a series, so the series object has to be fetched first and its ErrorBar method called on it. The steps are:
- Load the font and the test data file into the VFS.
- Load the workbook and get the first worksheet.
- Add a line chart whose data range is the planned output column.
- Use the month column as the category labels.
- Add a percentage error bar to the series, setting its direction and amount, then save the workbook.
The complete code example below shows how to add percentage error bars to a line chart in React:
function App() {
const addPercentageErrorBar = 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 test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'ErrorBarChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a line chart whose data range is the planned output column
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.Line });
chart.ChartTitle = "Planned Output";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
chart.DataRange = sheet.Range.get("B1:B7");
chart.SeriesDataFromRange = false;
// Set the chart position on the worksheet
chart.TopRow = 9;
chart.BottomRow = 26;
chart.LeftColumn = 1;
chart.RightColumn = 9;
// Get the series and use the month column as its category labels
const serie = chart.Series.get(0);
serie.CategoryLabels = sheet.Range.get("A2:A7");
// Add a percentage error bar to the series: plus direction, 10% of the value
serie.ErrorBar({
bIsY: true,
include: xlsModule.ErrorBarIncludeType.Plus,
type: xlsModule.ErrorBarType.Percentage,
numberValue: 10.0,
});
// Save the workbook
const outputFileName = "PercentageErrorBar.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Percentage Error Bars</h1>
<button onClick={addPercentageErrorBar}>Start</button>
</div>
);
}
export default App;
After running, the effect of adding percentage error bars to a line chart:

Add standard error bars to a column chart
A standard error bar takes no percentage from you; it computes the standard error of the series itself, so a series with scattered values automatically gets longer error bars. That is the division of labour between the two kinds: the standard error bar describes how steady the data is, the percentage one describes how far you are willing to let it drift. Column charts are usually there to compare several groups side by side, and hanging a standard error bar on each group shows at a glance which one's readings cluster more tightly. The steps are:
- Load the font and the test data file into the VFS.
- Load the workbook and get the first worksheet.
- Add a column chart covering both the planned and the actual output columns.
- Add a standard error bar to each of the two series.
- Save the workbook.
The complete code example below shows how to add standard error bars to a column chart in React:
function App() {
const addStandardErrorBar = 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 test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'ErrorBarChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart covering both the planned and the actual output columns
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Planned vs. Actual Output";
chart.ChartTitleArea.IsBold = true;
chart.ChartTitleArea.Size = 12;
chart.DataRange = sheet.Range.get("B1:C7");
chart.SeriesDataFromRange = false;
// Set the chart position on the worksheet
chart.TopRow = 9;
chart.BottomRow = 26;
chart.LeftColumn = 1;
chart.RightColumn = 9;
// Get the first series and use the month column as its category labels
const serie = chart.Series.get(0);
serie.CategoryLabels = sheet.Range.get("A2:A7");
// Draw a standard error bar on the first series, minus direction
serie.ErrorBar({
bIsY: true,
include: xlsModule.ErrorBarIncludeType.Minus,
type: xlsModule.ErrorBarType.StandardError,
numberValue: 0.3,
});
// Draw a standard error bar on the second series as well, both directions
const serie2 = chart.Series.get(1);
serie2.ErrorBar({
bIsY: true,
include: xlsModule.ErrorBarIncludeType.Both,
type: xlsModule.ErrorBarType.StandardError,
numberValue: 0.5,
});
// Save the workbook
const outputFileName = "StandardErrorBar.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Standard Error Bars</h1>
<button onClick={addStandardErrorBar}>Start</button>
</div>
);
}
export default App;
After running, the effect of adding standard error bars to a column chart:

FAQ
Which directions do error bars support?
The direction comes from the include parameter of ErrorBar, which takes three values from ErrorBarIncludeType:
| Value | Effect |
|---|---|
Both |
Both directions, a segment drawn above and below the data point |
Minus |
Negative only, drawn below the data point |
Plus |
Positive only, drawn above the data point |
// Draw it in both directions
serie.ErrorBar({
bIsY: true,
include: xlsModule.ErrorBarIncludeType.Both,
type: xlsModule.ErrorBarType.Percentage,
numberValue: 10.0,
});
Direction only decides which side of the data point the error bar is drawn on, and does not change its length. The same parameters give the same error amount in all three directions.
Which error amount types are supported?
The error amount type comes from the type parameter of ErrorBar, which takes five values from ErrorBarType:
| Type | Description |
|---|---|
Fixed |
A fixed value, given by numberValue |
Percentage |
A percentage of each data point's value |
StandardDeviation |
A standard deviation, given by numberValue |
StandardError |
A standard error, computed from the series data; numberValue plays no part |
Custom |
Custom ranges,needs a different overload |
The first four take their amount in numberValue:
serie.ErrorBar({
bIsY: true,
include: xlsModule.ErrorBarIncludeType.Both,
type: xlsModule.ErrorBarType.StandardDeviation,
numberValue: 2,
});
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.
Multi-Level Labels with a Secondary Axis in React with JavaScript
2026-09-18 06:28:49 Written by liu taliaWhen the categories in a chart are themselves layered -- a region that contains months, or a year that contains quarters -- squeezing both columns into a single row of labels leaves the reader guessing which region or which month a data point belongs to. Layered data brings a second problem with it: sales run into the millions while a growth rate sits in the low teens, and on one shared value axis the growth rate flattens into a line pinned to the baseline. Multi-level category labels and the secondary axis solve these two problems respectively. Spire.XLS for JavaScript performs both directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialised.
Create a Chart with Multi-Level Category Labels
Multi-level category labels are drawn by the category axis, and how many levels that axis has depends on how many columns the series' category labels point at. In the test data the outer labels are already merged by region, so the code only has to make the category labels span both the outer and the inner column. The steps are:
- Load the font and the test data file into the VFS.
- Load the workbook and get the worksheet.
- Add a column chart and add a named sales series.
- Point the category labels at both the region and the month column.
- Turn on multi-level labels for the category axis and save the workbook.
The complete code example below creates a chart with multi-level category labels in React:
function App() {
const createMultiLevelChart = 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 test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales";
chart.Legend.Delete();
// Add the sales series and give it a name
const serie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
serie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
serie.CategoryLabels = sheet.Range.get("A2:B7");
// Turn on multi-level category labels so each level gets its own row
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "MultiLevelLabels.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Multi-Level Labels</h1>
<button onClick={createMultiLevelChart}>Start</button>
</div>
);
}
export default App;
How many levels the category axis has is decided by how many columns CategoryLabels points at, so binding a single-column range still yields a single level of labels; MultiLevelLable controls whether those levels are laid out as multiple rows.
After running, the effect of creating a chart with multi-level category labels:

Add a Secondary Axis to the Chart
When two series in the same chart differ sharply in magnitude, sharing one value axis squashes the smaller of the two into a line pinned to the baseline, and its movement can no longer be read. A secondary axis is meant for exactly that case: it gives the series a value axis of its own, so each scale spreads across its own range without interfering with the other. The way to do it is to move the series off the primary axis and draw it as a line -- a line takes up no bar width, so it reads clearly against the column series sharing the same categories. The steps are:
- Load the font and the test data file into the VFS.
- Load the workbook and get the worksheet.
- Add a column chart and add a named sales series.
- Add the growth series as a line.
- Move the growth series to the secondary axis and save the workbook.
The complete code example below adds a secondary axis to the chart in React:
function App() {
const addSecondaryAxis = 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 test data file into the VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
const inputFileName = 'MultiLevelChartData.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
// Load the workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Add a column chart
const chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.ColumnClustered });
chart.ChartTitle = "Sales and YoY Growth";
// Add the sales series, which stays on the primary axis
const salesSerie = chart.Series.Add({ name: "Sales", serieType: xlsModule.ExcelChartType.ColumnClustered });
salesSerie.Values = sheet.Range.get("C2:C7");
// Point the category labels at both the region and the month column
salesSerie.CategoryLabels = sheet.Range.get("A2:B7");
// Add the growth series as a line
const growthSerie = chart.Series.Add({ name: "YoY Growth", serieType: xlsModule.ExcelChartType.Line });
growthSerie.Values = sheet.Range.get("D2:D7");
// Move the growth series to the secondary axis so it plots on its own percentage scale
growthSerie.UsePrimaryAxis = false;
// Turn on multi-level category labels
chart.PrimaryCategoryAxis.MultiLevelLable = true;
// Place the chart on the worksheet
chart.LeftColumn = 5;
chart.TopRow = 1;
chart.RightColumn = 14;
// Save the workbook
const outputFileName = "SecondaryAxis.xlsx";
workbook.SaveToFile({ fileName: outputFileName });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Secondary Axis</h1>
<button onClick={addSecondaryAxis}>Start</button>
</div>
);
}
export default App;
UsePrimaryAxis = false affects only the series it is set on; the other series stay on the primary axis. The chart gains a second pair of value and category axes as a result, giving it two separate scale ranges. Series.Add takes the series name at the same time, so the legend shows the name passed in rather than an auto-generated "Series 1".
After running, the effect of adding a secondary axis to the chart:

Frequently Asked Questions
Why does the category axis show only one level of labels?
Cause: How many levels the category axis has is decided by the range CategoryLabels points at. If that is a single-column range such as B2:B7, the range holds only one level of category information, and setting PrimaryCategoryAxis.MultiLevelLable to true will still give you one level of labels -- the property controls whether multiple levels are expanded, not whether a level of data is created.
Solution: Point CategoryLabels at a multi-column range that includes the outer labels; the cells the outer labels occupy then need to be merged in the data:
// Cover both columns with the category labels; the outer label cells need merging in the data
serie.CategoryLabels = sheet.Range.get("A2:B7");
Why do the two value axes have different scales?
Cause: The primary and secondary value axes work out their scales independently of each other, and MinValue, MaxValue and MajorUnit on PrimaryValueAxis apply to the primary axis only -- changing them leaves the secondary axis untouched. When the two series differ sharply in magnitude, the range the secondary axis picks for itself is often not a good fit.
Solution: Give the secondary axis its own scale through chart.SecondaryValueAxis:
// Give the secondary axis a 0-20 scale with a major unit of 5
chart.SecondaryValueAxis.MinValue = 0;
chart.SecondaryValueAxis.MaxValue = 20;
chart.SecondaryValueAxis.MajorUnit = 5;
Set the scale after the series has been moved to the secondary axis: while no series uses the secondary axis, the assignment is accepted but never written to the file.
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.
Apply Color Scales & Icon Sets in Excel in React with JavaScript
2026-09-18 06:26:39 Written by liu taliaIn a sales report, a grade sheet, or a metrics dashboard, how values compare matters more than the values themselves. Inserting a chart for every column makes the worksheet crowded, while data bars, color scales, and icon sets show magnitude right inside the cells—through bar length, color intensity, and icon shape—without consuming extra rows or columns. All three belong to Excel conditional formatting, found under Home → Conditional Formatting in the Excel UI.Spire.XLS for JavaScript performs this work directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers three key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Apply Data Bars to a Cell Range
Data bars draw a horizontal colored band inside each cell, and the length of the band is proportional to how large the value is compared with the rest of the selected range. With Spire.XLS for JavaScript, ConditionalFormats.Add creates a conditional format collection, AddRange binds it to a range, and AddCondition returns the condition object; setting FormatType to ConditionalFormatType.DataBar produces data bars, whose fill color is controlled by DataBar.BarColor. The steps are as follows:
- Load the font and the test data file into the VFS.
- Load the workbook and get the worksheet.
- Call
ConditionalFormats.Addto create a conditional format, and bind the data range withAddRange. - Call
AddConditionto add a condition, setFormatTypetoDataBar, and set the bar color. - Save the workbook.
The complete code example below applies data bars to a sales figures table in React:
function App() {
const applyDataBars = 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 test data 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 first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the data bars
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a data bar condition and set the bar color
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.DataBar;
format.DataBar.BarColor = xlsModule.Color.get_CadetBlue();
// Save the workbook
const outputFileName = "ApplyDataBars.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Apply Data Bars</h1>
<button onClick={applyDataBars}>Start</button>
</div>
);
}
export default App;
After running, the effect of applying data bars to a cell range:
![]()
Apply Color Scales to a Cell Range
A color scale uses shading to express magnitude: the larger a cell's value is within the range, the closer its color sits to the high end of the scale. Color scales are added through the same ConditionalFormats API as data bars—the only difference is setting FormatType to ConditionalFormatType.ColorScale. No color arguments are required; when none are specified, the result is a two-color scale that takes orange at the range minimum and pale yellow at the maximum, with intermediate values shaded proportionally between the two. The steps are as follows:
- Load the font and the test data file into the VFS.
- Load the workbook and get the worksheet.
- Call
ConditionalFormats.Addto create a conditional format, and bind the data range withAddRange. - Call
AddConditionto add a condition, and setFormatTypetoColorScale. - Save the workbook.
The complete code example below applies color scales to a sales figures table in React:
function App() {
const applyColorScales = 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 test data 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 first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the color scales
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add a color scale condition; colors transition with the values
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.ColorScale;
// Save the workbook
const outputFileName = "ApplyColorScales.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Apply Color Scales</h1>
<button onClick={applyColorScales}>Start</button>
</div>
);
}
export default App;
After running, the effect of applying color scales to a cell range:
![]()
Apply Icon Sets to a Cell Range
An icon set places a different icon in each cell according to the band its value falls into—for example, red, yellow, and green traffic lights for low, medium, and high. It uses the same API: set FormatType to ConditionalFormatType.IconSet and pick an icon style with IconSet.IconSetType; the example uses IconSetType.ThreeTrafficLights1. The steps are as follows:
- Load the font and the test data file into the VFS.
- Load the workbook and get the worksheet.
- Call
ConditionalFormats.Addto create a conditional format, and bind the data range withAddRange. - Call
AddConditionto add a condition, setFormatTypetoIconSet, and specify the icon set type. - Save the workbook.
The complete code example below applies icon sets to a sales figures table in React:
function App() {
const applyIconSets = 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 test data 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 first worksheet
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile({ fileName: inputFileName });
const sheet = workbook.Worksheets.get(0);
// Select the data range that receives the icon sets
const dataRange = sheet.Range.get("B2:E9");
// Create a conditional format and bind it to that range
const xcfs = sheet.ConditionalFormats.Add();
xcfs.AddRange(dataRange);
// Add an icon set condition and set the icon style to three traffic lights
const format = xcfs.AddCondition();
format.FormatType = xlsModule.ConditionalFormatType.IconSet;
format.IconSet.IconSetType = xlsModule.IconSetType.ThreeTrafficLights1;
// Save the workbook
const outputFileName = "ApplyIconSets.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Apply Icon Sets</h1>
<button onClick={applyIconSets}>Start</button>
</div>
);
}
export default App;
An icon set divides the range into bands, so the same icon covers a different span of values in different ranges.
After running, the effect of applying icon sets to a cell range:
![]()
FAQ
Why do the text cells in the target range get no data bars?
Cause: A data bar expresses how large a value is relative to the rest of the range, so only numeric cells are shaded and text cells inside the range are skipped. Even when the range covers the product-name column or the header row, those cells show no bars—the result still covers the numeric area alone.
Solution: This is the expected behavior and needs no workaround; just keep the range limited to the numeric area. If the numeric area itself shows no bars either, check that the range passed to AddRange matches where the data actually is.
Can the color and border of a data bar be customized?
Cause: A data bar's appearance is controlled by the DataBar property of the condition object. The fill color comes from DataBar.BarColor; setting only FormatType without BarColor yields the default blue bars. Data bars have no border by default, so assigning BarBorder.Color on its own has no effect.
Solution: Set the border type through DataBar.BarBorder.Type first, then set the border color—the two go together:
// Set the border type first so that the border color takes effect
format.DataBar.BarBorder.Type = xlsModule.DataBarBorderType.DataBarBorderSolid;
format.DataBar.BarBorder.Color = xlsModule.Color.get_Red();
// Fill color of the bar
format.DataBar.BarColor = xlsModule.Color.get_GreenYellow();
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.
Besides holding cell data, an Excel workbook is often used as a container for files: a quotation carries a Word version of the contract terms, a product sheet carries a PDF datasheet, and double-clicking the object opens the source file directly. Files embedded into a worksheet like this are OLE objects (Object Linking and Embedding). Inserting one by hand takes two steps in the Excel UI—Insert → Object—but doing it from code in the browser needs a dedicated API.Spire.XLS for JavaScript performs this work directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Insert an OLE Object in Excel
OleObjects.Add inserts an external file into a worksheet. It takes three arguments: the file to embed, the icon the object shows on the sheet, and the link type—OleLinkType.Embed embeds the file into the workbook, OleLinkType.Link inserts it as a link. After the object is in place, Location decides which cell it is anchored to and ObjectType declares what was embedded, which is how Excel knows which program to use when the object is double-clicked. The steps are:
- Create a new workbook and write a caption into a cell.
- Open the workbook to be embedded and render its worksheet to an image, to use as the display icon.
- Embed that Excel file into the worksheet with
OleObjects.Add. - Set
LocationandObjectType. - Save the workbook.
Here is a complete code example that inserts an Excel file into a worksheet as an OLE object in React:
function App() {
const insertOleObject = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file to be embedded into VFS
const embeddedFileName = 'OLEObjects.xlsx';
await window.spire.FetchFileToVFS(embeddedFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Create a new workbook and write the caption
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
sheet.Range.get("A1").Text = "Here is an OLE object.";
// Open the embedded workbook and render its worksheet to an image as the display icon
const embeddedBook = new xlsModule.Workbook();
embeddedBook.LoadFromFile(embeddedFileName);
const embeddedSheet = embeddedBook.Worksheets.get(0);
embeddedSheet.PageSetup.LeftMargin = 0;
embeddedSheet.PageSetup.RightMargin = 0;
embeddedSheet.PageSetup.TopMargin = 0;
embeddedSheet.PageSetup.BottomMargin = 0;
const image = embeddedSheet.ToImage(1, 1, 19, 5);
embeddedBook.Dispose();
// Embed the Excel file into the worksheet; the file data is stored with the workbook
const oleObject = sheet.OleObjects.Add(
embeddedFileName,
image,
xlsModule.OleLinkType.Embed
);
// Anchor the object at cell B4 and declare it as an Excel worksheet
oleObject.Location = sheet.Range.get("B4");
oleObject.ObjectType = xlsModule.OleObjectType.ExcelWorksheet;
// Save the workbook
const outputFileName = "InsertOLEObject.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the result 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>Insert an OLE Object</h1>
<button onClick={insertOleObject}>Start</button>
</div>
);
}
export default App;
The icon here is taken directly from the rendered embedded worksheet, so the OLE object shows its own content on the sheet. Switching ObjectType to values such as OleObjectType.WordDocument or OleObjectType.AdobeAcrobatDocument declares other kinds of embedded files.
Running it, the effect of inserting a workbook as an OLE object:

Insert an OLE Object with a Custom Icon
ToImage has to open a workbook and render a row/column range every time, which suits cases where the object should present its own content; when a single icon should be applied to every attachment, reading a ready-made picture is simpler, and the same picture can be reused across attachments. The second argument of OleObjects.Add accepts both kinds of input. The steps are:
- Load the icon image and the attachment file into VFS.
- Create a new workbook and read the icon image into a stream with
new xlsModule.Stream. - Insert the attachment as an embedded object with
OleObjects.Add, passing the icon stream. - Set
LocationandObjectType. - Save the workbook.
Here is a complete code example that inserts a PDF attachment with a custom icon in React:
function App() {
const insertOleObjectWithIcon = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the icon image and the attachment into VFS
const iconFileName = 'OLEIcon.png';
const attachmentFileName = 'Attachment.pdf';
await window.spire.FetchFileToVFS(iconFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
await window.spire.FetchFileToVFS(attachmentFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Create a new workbook
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Read the icon image as a stream to use as the display icon of the OLE object
const iconStream = new xlsModule.Stream(iconFileName);
// Embed the PDF attachment into the worksheet
const oleObject = sheet.OleObjects.Add(
attachmentFileName,
iconStream,
xlsModule.OleLinkType.Embed
);
// Anchor the object at cell B4 and declare it as a PDF document
oleObject.Location = sheet.Range.get("B4");
oleObject.ObjectType = xlsModule.OleObjectType.AdobeAcrobatDocument;
// Save the workbook
const outputFileName = "InsertOLEObjectWithIcon.xlsx";
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the result 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>Insert an OLE Object with a Custom Icon</h1>
<button onClick={insertOleObjectWithIcon}>Start</button>
</div>
);
}
export default App;
Running it, the effect of inserting a PDF attachment with a custom icon as an OLE object:

FAQ
Only a blank icon shows up on the sheet after inserting?
Cause: The second argument of OleObjects.Add decides the icon an OLE object shows on the sheet. When the image comes from ToImage, a region that falls outside the used range of the worksheet yields a blank picture, so the inserted object also shows only blank space.
Solution: Keep the region inside the part of the sheet that actually has content, or use a ready-made image file instead:
// Use a fixed picture as the icon, independent of the worksheet content
const iconStream = new xlsModule.Stream('OLEIcon.png');
const oleObject = sheet.OleObjects.Add('Attachment.pdf', iconStream, xlsModule.OleLinkType.Embed);
oleObject.Location = sheet.Range.get("B4");
oleObject.ObjectType = xlsModule.OleObjectType.AdobeAcrobatDocument;
What happens if ObjectType is set to something else?
Cause: ObjectType is not merely a comment—its value is written into the progId field of the workbook, and Excel uses that identifier to find the right program when the object is double-clicked. The same PDF attachment declares a progId of Acrobat Document under OleObjectType.AdobeAcrobatDocument; declare it as OleObjectType.ExcelWorksheet and the progId becomes Worksheet, so Excel attempts to open the PDF with Excel itself, and the object will not open.
Solution: Set ObjectType to the real type of the embedded file. The common values are:
| Embedded file | ObjectType |
|---|---|
| Excel workbook | OleObjectType.ExcelWorksheet |
| Word document | OleObjectType.WordDocument |
| PowerPoint presentation | OleObjectType.PowerPointSlide |
| PDF document | OleObjectType.AdobeAcrobatDocument |
// Declare the real file type so Excel opens it with the right program
oleObject.ObjectType = xlsModule.OleObjectType.AdobeAcrobatDocument;
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.
Compress, Resize or Move Excel Pictures in React with JavaScript
2026-09-18 01:57:13 Written by AdministratorOnce a report has accumulated a few pictures, the awkward part is rarely the text: a few hundred kilobytes of product photos pushed straight into a worksheet will swell the file until sending and archiving become painful, and pictures copied in from elsewhere rarely share one size—a large one covers an entire block of data while a small one sits unreadable in a corner. Fixing these by hand in Excel is bearable, but there is no entry point once the work has to be done in code.Spire.XLS for JavaScript performs this work directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers three key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Compress Pictures in Excel
Compress() re-encodes a picture at the quality ratio you pass in: a value of 50 brings the picture quality down to 50%. The lower the quality, the less data the picture takes up and the lighter the workbook becomes. Compression only touches the picture's own data—the picture keeps its position and its display size on the worksheet—so it is the right move when you want a smaller file without disturbing the layout. The steps are:
- Load the workbook.
- Walk every picture of every worksheet.
- Call
Compressto bring each picture down to 50% quality. - Save the workbook.
The following is a complete code example that compresses the pictures in an Excel file in React:
function App() {
const compressPictures = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'ResizeAndMovePictures.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile(inputFileName);
// Walk every picture of every worksheet
for (const sheet of workbook.Worksheets) {
for (const picture of sheet.Pictures) {
// Compress the picture quality down to 50%
picture.Compress(50);
}
}
// Save the workbook
const outputFileName = "CompressPictures.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Compress, Resize or Move Pictures in Excel</h1>
<button onClick={compressPictures}>Start</button>
</div>
);
}
export default App;
Compress handles every picture it reaches in one pass; the compressed pictures stay where they were and only lose some image quality.
After running, the effect of compressing pictures in Excel:

Resize a Picture in Excel
The size a picture is displayed at on a worksheet is controlled by two properties, Width and Height, measured in pixels. Assigning new values to them brings the picture to the size you want—a shrunken picture no longer covers the data next to it, and an enlarged one can fill a reserved picture slot. The steps are:
- Load the workbook and get the first worksheet.
- Get the first picture of the worksheet with
sheet.Pictures.get(0). - Set
WidthandHeightto resize the picture. - Save the workbook.
The following is a complete code example that resizes a picture in Excel in React:
function App() {
const resizePicture = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'ResizeAndMovePictures.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
const sheet = workbook.Worksheets.get(0);
// Get the first picture of the worksheet
const picture = sheet.Pictures.get(0);
// Resize the picture to 140 pixels wide and 140 pixels high
picture.Width = 140;
picture.Height = 140;
// Save the workbook
const outputFileName = "ResizePicture.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Compress, Resize or Move Pictures in Excel</h1>
<button onClick={resizePicture}>Start</button>
</div>
);
}
export default App;
Width and Height map to the picture's width and height and take effect independently, so the picture shows at its new size as soon as they are assigned. Note that this sets the size of the picture frame rather than scaling proportionally—when the new width and height do not match the original ratio, the picture is stretched. See the FAQ below for how to handle that.
After running, the effect of resizing a picture in Excel:

Move a Picture in Excel
A picture in Excel is a floating object anchored to a cell, so setting its size alone does not change where it shows up. The Left and Top properties are measured in pixels and give the distance from the top-left corner of the worksheet to the top-left corner of the picture; assigning them moves the picture to the new coordinates, which is how you push a picture out of a block of data or line several pictures up in the same column. The steps are:
- Load the workbook and get the first worksheet.
- Get the first picture of the worksheet with
sheet.Pictures.get(0). - Set
LeftandTopto move the picture. - Save the workbook.
The following is a complete code example that moves a picture in Excel in React:
function App() {
const movePicture = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'ResizeAndMovePictures.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
const sheet = workbook.Worksheets.get(0);
// Get the first picture of the worksheet
const picture = sheet.Pictures.get(0);
// Move the top-left corner of the picture 360 pixels from the left and 180 pixels from the top
picture.Left = 360;
picture.Top = 180;
// Save the workbook
const outputFileName = "MovePicture.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Compress, Resize or Move Pictures in Excel</h1>
<button onClick={movePicture}>Start</button>
</div>
);
}
export default App;
Left and Top describe the absolute coordinates of the picture's top-left corner on the worksheet, regardless of which row or column the picture was originally anchored to.
After running, the effect of moving a picture in Excel:

FAQ
Why does a picture look stretched after resizing?
Cause: Width and Height are two independent properties, and assigning them separately does not preserve the picture's original aspect ratio. Give a rectangular picture the same value for width and height and it is forced into a square.
Solution: read the picture's current width and height first, work out the ratio, and derive the other dimension from it. The size properties only accept integers, so round the result:
// Read the picture's current width and height to work out the ratio
const picture = sheet.Pictures.get(0);
const ratio = picture.Height / picture.Width;
// Fix the width and derive the height from the ratio so the picture is not distorted
picture.Width = 140;
picture.Height = Math.round(140 * ratio);
Does IsLockAspectRatio keep a picture from being distorted?
Cause: no. The property is true by default, and what it sets is the picture's lock flag, which constrains resizing by hand in Excel. It does not scale the other side for you when Width / Height are assigned from code—setting Width to 140 left Height at its original 300 whether IsLockAspectRatio was true or false.
Solution: proportional resizing still has to be computed by hand. The property reads and writes fine and survives a save, so set it when the file's lock state needs to match:
// The lock flag: true by default; setting it to false is written to the file and reads back as false
picture.IsLockAspectRatio = false;
// But it takes no part in the width / height conversion: change Width alone and Height stays put
picture.Width = 140;
// To scale proportionally, work out the ratio first
const ratio = picture.Height / picture.Width;
picture.Width = 140;
picture.Height = Math.round(140 * ratio);
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.
Autofit Row Heights and Column Widths in React with JavaScript
2026-09-18 01:55:27 Written by liu taliaOnce the data is in, a table usually needs one last pass before it is usable: a product name squeezed into a sliver of a column, a paragraph of remarks running along a single line until the next non-empty cell cuts it off. Dragging column borders and row dividers by hand is slow, and once there are enough columns it is easy to miss a few. Spire.XLS for JavaScript performs this work directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers two key features:
- Autofit the Height of a Single Row and the Width of a Single Column
- Autofit the Heights of Multiple Rows and the Widths of Multiple Columns
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Autofit the Height of a Single Row and the Width of a Single Column
AutoFitRow works out the height of the given row from its content, and AutoFitColumn works out the width of the given column the same way. Each one affects only the row or the column it is pointed at and leaves the rest of the table untouched, which is what you want when a single overflow is the only thing in the way.
Note that row height autofit only means anything for content that needs to wrap: with wrapping turned off the text always sits on one line and the height simply follows the font size, so there is no taller value to calculate. The steps are:
- Load the workbook and get the first worksheet.
- Autofit the height of that row with
AutoFitRow. - Autofit the width of that column with
AutoFitColumn. - Save the workbook.
Here is a complete code example that autofits the height of a single row and the width of a single column in React:
function App() {
const autoFitSingleRowColumn = 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/`);
// Load the Excel file into the VFS
const inputFileName = 'AutoFitRowsAndColumns.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
const sheet = workbook.Worksheets.get(0);
// Autofit the height of row 2
sheet.AutoFitRow(2);
// Autofit the width of column 4
sheet.AutoFitColumn(4);
// Save the workbook
const outputFileName = "AutoFitSingleRowColumn.xlsx";
workbook.SaveToFile(outputFileName);
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Autofit Row Height and Column Width</h1>
<button onClick={autoFitSingleRowColumn}>Start</button>
</div>
);
}
export default App;
After running, the effect of autofitting a single row height and a single column width:

Autofit the Heights of Multiple Rows and the Widths of Multiple Columns
When the whole table needs tidying, calling the methods row by row is not realistic. Calling AutoFitRows or AutoFitColumns on a range recalculates every row and every column the range covers from its own content, so a single call lines up the whole block — the kind of pass you want before exporting a report. The steps are:
- Load the workbook and get the first worksheet.
- Autofit the heights of the rows with
AutoFitRows. - Autofit the widths of the columns with
AutoFitColumns. - Save the workbook.
Here is a complete code example that autofits the heights of multiple rows and the widths of multiple columns in React:
function App() {
const autoFitMultipleRowsColumns = 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/`);
// Load the Excel file into the VFS
const inputFileName = 'AutoFitRowsAndColumns.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
const sheet = workbook.Worksheets.get(0);
// Get the used range of the worksheet
const range = sheet.AllocatedRange;
// Autofit the height of every row in the range
range.AutoFitRows();
// Autofit the width of every column in the range
range.AutoFitColumns();
// Save the workbook
const outputFileName = "AutoFitMultipleRowsColumns.xlsx";
workbook.SaveToFile(outputFileName);
// Dispose of the workbook object to free resources
workbook.Dispose();
// Read the result 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>Autofit Row Height and Column Width</h1>
<button onClick={autoFitMultipleRowsColumns}>Start</button>
</div>
);
}
export default App;
After running, the effect of autofitting multiple row heights and multiple column widths:

FAQ
I called AutoFitRow() and the row height did not change at all?
Cause: Row height autofit only applies to content that needs to wrap. With wrapping turned off the text stays on a single line and the height follows the font size, so autofit arrives at the same value as the existing height and appears to have done nothing.
Solution: Set WrapText to true first, then autofit the row height:
// With wrapping off, autofitting the row height changes nothing
sheet.Range.get("D2").Style.WrapText = false;
sheet.AutoFitRow(2);
// With wrapping on, the height is recalculated from the wrapped line count
sheet.Range.get("D2").Style.WrapText = true;
sheet.AutoFitRow(2);
AutoFitColumns() has no effect on merged cells?
Cause: Column width autofit measures the content of individual cells. In a merged range only the top-left cell actually holds text and every other position in the range is empty, so the width it works out is only enough for that top-left content.
Solution: Set the width of a merged range by hand with ColumnWidth:
// A7:D7 is a merged range, so autofit cannot work out its combined width
sheet.Range.get("A7:D7").Merge();
sheet.Range.get("A7:D7").AutoFitColumns();
// Set the column width by hand so the merged text fits
sheet.Range.get("A7").ColumnWidth = 40;
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.
Modify, Hide and Delete Named Ranges in React with JavaScript
2026-09-17 05:55:53 Written by liu taliaA named range is not something you set up once and forget. As the data table is restructured, the original name may no longer fit, and the referred range can go stale when rows are added or removed. Some named ranges exist only as an intermediate helper for a formula and have no business showing up in the Name Manager. And named ranges that are no longer used, if kept forever, turn the name list into something long and hard to search. Modifying, hiding and deleting are therefore just as much a part of working with named ranges as creating them. Spire.XLS for JavaScript provides a complete named range management API and can perform all of the above in the browser through WebAssembly, with no backend service required.
This article covers three key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Modify a Named Range
Modifying covers two independent aspects: the name itself and the referred range. The name is reassigned through the Name property and the referred range through the RefersToRange property. The two can be changed separately, or together as in the example below. The steps are:
- Load the workbook and get the first worksheet.
- Take the named range to modify with
workbook.NameRanges.get(0). - Set
Nameto the new name. - Point
RefersToRangeat the new cell range. - Save the workbook.
The following is a complete code example that shows how to modify a named range in React:
function App() {
const modifyNamedRange = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'AllNamedRanges.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);
// Change the name of the named range
workbook.NameRanges.get(0).Name = "RegionData";
// Change the cell range the named range refers to
workbook.NameRanges.get(0).RefersToRange = sheet.Range.get("B2:C4");
// Save the workbook
const outputFileName = 'ModifyNamedRange.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Modify Named Range</h1>
<button onClick={modifyNamedRange}>Start</button>
</div>
);
}
export default App;
After running, the effect of modifying a named range:

Hide a Named Range
Set the Visible property to false and the named range is hidden. A hidden named range is still stored in the workbook and formulas that refer to it are unaffected — it simply no longer appears in Excel's Name Manager and name box, which keeps the name list tidy. After hiding it, the example below also writes the formula =SUM(NameRange1) into cell F2: the formula still calculates normally, which is exactly what shows that the named range is only hidden, not deleted. The steps are:
- Load the workbook and get the first worksheet.
- Take the named range to hide.
- Set
Visibletofalse. - Write a formula that refers to the named range into a cell, to confirm it still works.
- Save the workbook.
The following is a complete code example that shows how to hide a named range in React:
function App() {
const hideNamedRange = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'AllNamedRanges.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);
// Hide the first named range
workbook.NameRanges.get(0).Visible = false;
// Write a formula that refers to the hidden named range, proving it still exists and works
sheet.Range.get("F1").Text = "Sum After Hiding";
sheet.Range.get("F2").Formula = "=SUM(NameRange1)";
// Calculate the formulas so the saved file shows the result as soon as it is opened
workbook.CalculateAllValue();
// Save the workbook
const outputFileName = 'HideNamedRange.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Hide Named Range</h1>
<button onClick={hideNamedRange}>Start</button>
</div>
);
}
export default App;
After running, the effect of hiding a named range:

Note: The formula in cell F2 refers to the hidden NameRange1, and it still calculates 120. That shows the named range has only been hidden from view, not removed from the workbook.
Delete a Named Range
There are two ways to delete a named range: call Remove() when the name is known, or RemoveAt() when the position is known. Both remove the named range from the workbook entirely. The steps are:
- Load the workbook.
- Call
Remove()to delete a named range by name. - Call
RemoveAt()to delete a named range by index. - Save the workbook.
The following is a complete code example that shows how to delete a named range in React:
function App() {
const deleteNamedRange = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'AllNamedRanges.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
// Load the workbook
const workbook = new xlsModule.Workbook();
workbook.LoadFromFile(inputFileName);
// Delete a named range by name
workbook.NameRanges.Remove("NameRange2");
// Delete a named range by index
workbook.NameRanges.RemoveAt(0);
// Save the workbook
const outputFileName = 'DeleteNamedRange.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Delete Named Range</h1>
<button onClick={deleteNamedRange}>Start</button>
</div>
);
}
export default App;
After running, the effect of deleting a named range:

FAQ
Why is the result of a formula missing when the saved file is opened?
Cause: Setting only the Formula property of a cell does not make Spire calculate it. The saved file then contains the formula itself but no calculated result value, so the cell comes up blank when the file is opened.
Solution: Call workbook.CalculateAllValue() before saving, to evaluate the formulas first:
// Calculate all formulas so the result value is written into the saved file
workbook.CalculateAllValue();
Can I pass a named range object to the delete API?
Cause: Remove() takes a name string. Passing a NameRange object does not match the expected type and throws Assert failed: Value is not a String, and nothing is deleted.
Solution: Pass the name when it is known, or the index when the position is known:
// Delete by name
workbook.NameRanges.Remove("NameRange2");
// Delete by index
workbook.NameRanges.RemoveAt(0);
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.
Set the Alignment, Indent, Orientation and Wrapping of Excel Cell Text in React with JavaScript
2026-09-17 05:55:07 Written by liu taliaHow readable a table is often has nothing to do with the data itself and everything to do with how the text sits inside its cells. Titles need to be centred, amounts need to be pushed right, multi-line descriptions need to be indented, a long sentence in a narrow column needs to fold, and a header set at an angle fits more information into limited column width. All of these are cell text layout settings. Spire.XLS for JavaScript performs them directly in the browser through WebAssembly, managing input and output files with a virtual file system (VFS) and requiring no backend service.
This article covers four key features:
- Set the Alignment of Text
- Set the Indent of Text
- Set the Orientation of Text
- Set the Wrapping of Text
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Set the Alignment of Text
Alignment works along two axes. Vertical alignment decides where the text sits within the height of the cell and is set through the VerticalAlignment property, which accepts Top, Center, Bottom and others. Horizontal alignment decides where the text sits within the width of the cell and is set through the HorizontalAlignment property, which accepts General, Left, Center, Right and others. The two are independent and can be combined freely. The steps are as follows:
- Create a workbook and get the first worksheet.
- Write the sample text.
- Set the vertical alignment through
VerticalAlignment. - Set the horizontal alignment through
HorizontalAlignment. - Save the workbook.
Here is a complete code example that sets the alignment of cell text in React:
function App() {
const setTextAlignment = 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 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 the sample text for vertical alignment
sheet.Range.get("A1").Text = "Alignment";
sheet.Range.get("B1").Text = "Sample";
sheet.Range.get("A2").Text = "Vertical Top";
sheet.Range.get("B2").Text = "VerticalAlignType.Top";
sheet.Range.get("A3").Text = "Vertical Center";
sheet.Range.get("B3").Text = "VerticalAlignType.Center";
sheet.Range.get("A4").Text = "Vertical Bottom";
sheet.Range.get("B4").Text = "VerticalAlignType.Bottom";
// Write the sample text for horizontal alignment
sheet.Range.get("A6").Text = "Horizontal General";
sheet.Range.get("B6").Text = "HorizontalAlignType.General";
sheet.Range.get("A7").Text = "Horizontal Left";
sheet.Range.get("B7").Text = "HorizontalAlignType.Left";
sheet.Range.get("A8").Text = "Horizontal Center";
sheet.Range.get("B8").Text = "HorizontalAlignType.Center";
sheet.Range.get("A9").Text = "Horizontal Right";
sheet.Range.get("B9").Text = "HorizontalAlignType.Right";
// Set the vertical alignment
sheet.Range.get("B2").Style.VerticalAlignment = xlsModule.VerticalAlignType.Top;
sheet.Range.get("B3").Style.VerticalAlignment = xlsModule.VerticalAlignType.Center;
sheet.Range.get("B4").Style.VerticalAlignment = xlsModule.VerticalAlignType.Bottom;
// Set the horizontal alignment
sheet.Range.get("B6").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.General;
sheet.Range.get("B7").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Left;
sheet.Range.get("B8").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Center;
sheet.Range.get("B9").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Right;
// Widen column B and raise rows 2-4 so the alignment differences are visible
sheet.Range.get("B1:B9").ColumnWidth = 32;
sheet.Range.get("A2:B4").RowHeight = 40;
// Save the workbook
const outputFileName = "TextAlignment.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Set Text Alignment</h1>
<button onClick={setTextAlignment}>Start</button>
</div>
);
}
export default App;
Vertical alignment is only visible once the row is tall enough, which is why the example sets rows 2-4 to a height of 40; horizontal alignment is at its clearest once the column is wide enough.
After running, the effect of setting the alignment of text:

Set the Indent of Text
Indentation leaves blank space on the left (or right) inside a cell, which suits data that has a hierarchy, such as "region → city". The indent level is set through the IndentLevel property, where one level is roughly one character wide. The steps are as follows:
- Create a workbook and get the first worksheet.
- Write the sample text.
- Set the horizontal alignment to left so the indentation takes effect.
- Set an increasing indent level through
IndentLevel. - Save the workbook.
Here is a complete code example that sets the indent of cell text in React:
function App() {
const setTextIndent = 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 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 the sample text
sheet.Range.get("A1").Text = "Indent Level";
sheet.Range.get("B1").Text = "Sample";
sheet.Range.get("A2").Text = "0";
sheet.Range.get("B2").Text = "Worldwide";
sheet.Range.get("A3").Text = "1";
sheet.Range.get("B3").Text = "North Region";
sheet.Range.get("A4").Text = "2";
sheet.Range.get("B4").Text = "Beijing";
sheet.Range.get("A5").Text = "3";
sheet.Range.get("B5").Text = "Haidian District";
// Indentation only takes effect together with left alignment
sheet.Range.get("B2:B5").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Left;
// Set the indentation level of the text
sheet.Range.get("B2").Style.IndentLevel = 0;
sheet.Range.get("B3").Style.IndentLevel = 1;
sheet.Range.get("B4").Style.IndentLevel = 2;
sheet.Range.get("B5").Style.IndentLevel = 3;
// Widen column B so the indentation differences are visible
sheet.Range.get("B1:B5").ColumnWidth = 32;
// Save the workbook
const outputFileName = "Indentation.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Set Text Indent</h1>
<button onClick={setTextIndent}>Start</button>
</div>
);
}
export default App;
The four rows step in one level at a time, forming exactly the hierarchy "Worldwide → North Region → Beijing → Haidian District". Cell B5 has an IndentLevel of 3, so its text starts about three characters in from the left edge.
After running, the effect of setting the indent of text:

Set the Orientation of Text
Text orientation covers two independent settings. The first is the rotation angle, set through the Rotation property, where values 0 to 90 are degrees counterclockwise and -1 to -90 are degrees clockwise. There is also the special value 255, which stacks the text vertically one character per line; rotation is often used to fit a long header into a narrow column. The second is the reading order, set through the ReadingOrder property, which accepts LeftToRight, RightToLeft and Context. It decides which direction the mixed content in a cell is laid out from, and is used for languages written from right to left such as Arabic and Hebrew. Rotated or stacked text takes up far more height than usual, so the row height has to be raised at the same time to keep the text inside the cell. The steps are as follows:
- Create a workbook and get the first worksheet.
- Write the sample text.
- Set the rotation angle through
Rotation. - Set the reading order through
ReadingOrder. - Save the workbook.
Here is a complete code example that sets the orientation of cell text in React:
function App() {
const setTextOrientation = 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 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 the sample text for the rotation angle
sheet.Range.get("A1").Text = "Text Orientation";
sheet.Range.get("B1").Text = "Sample";
sheet.Range.get("A2").Text = "Counterclockwise 45";
sheet.Range.get("B2").Text = "Rotation = 45";
sheet.Range.get("A3").Text = "Counterclockwise 90";
sheet.Range.get("B3").Text = "Rotation = 90";
sheet.Range.get("A4").Text = "Clockwise 45";
sheet.Range.get("B4").Text = "Rotation = -45";
sheet.Range.get("A5").Text = "Stacked";
sheet.Range.get("B5").Text = "Spire";
// Write the sample text for the reading order: Latin mixed with Hebrew, so the
// difference between the two directions is actually visible
sheet.Range.get("A7").Text = "Left to Right";
sheet.Range.get("B7").Text = "Spire.XLS שלום";
sheet.Range.get("A8").Text = "Right to Left";
sheet.Range.get("B8").Text = "Spire.XLS שלום";
// Set the rotation angle of the text; 255 stacks the text vertically
sheet.Range.get("B2").Style.Rotation = 45;
sheet.Range.get("B3").Style.Rotation = 90;
sheet.Range.get("B4").Style.Rotation = -45;
sheet.Range.get("B5").Style.Rotation = 255;
// Set the reading order of the text
sheet.Range.get("B7").Style.ReadingOrder = xlsModule.ReadingOrderType.LeftToRight;
sheet.Range.get("B8").Style.ReadingOrder = xlsModule.ReadingOrderType.RightToLeft;
// Widen column B and raise rows 2-5 so the rotated and stacked text fits
sheet.Range.get("B1:B8").ColumnWidth = 20;
sheet.Range.get("A2:B5").RowHeight = 60;
// Save the workbook
const outputFileName = "TextOrientation.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Set Text Orientation</h1>
<button onClick={setTextOrientation}>Start</button>
</div>
);
}
export default App;
In the example, B2, B3 and B4 are rotated 45 degrees, 90 degrees and -45 degrees respectively, and B5 uses a Rotation of 255, which stacks the text into a column running top to bottom; all five rows are given a height of 60. B7 and B8 hold the same mixed Latin and Hebrew string with opposite reading orders, and the Hebrew ends up on opposite sides in the two rows — which is exactly what reading order does to mixed content.
After running, the effect of setting the orientation of text:

Set the Wrapping of Text
When a piece of text is longer than the column, it spills over onto the neighbouring empty cell by default, and is cut off as soon as that neighbour has content of its own. Setting the WrapText property to true folds the text inside the cell instead; setting it to false returns the text to a single line. As with rotation, wrapping only changes how the text is laid out and does not adjust the row height by itself, so the row height is usually raised as well to show every folded line in full. The steps are as follows:
- Create a workbook and get the first worksheet.
- Write a long piece of text.
- Turn wrapping on or off through
WrapText. - Adjust the column width and row height so the folding is fully visible.
- Save the workbook.
Here is a complete code example that sets the wrapping of cell text in React:
function App() {
const setTextWrap = 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 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 the sample text
sheet.Range.get("A1").Text = "Wrap Text";
sheet.Range.get("B1").Text = "Sample";
sheet.Range.get("A2").Text = "On";
sheet.Range.get("B2").Text = "Spire.XLS for JavaScript can wrap text inside a cell in the browser.";
sheet.Range.get("A3").Text = "Off";
sheet.Range.get("B3").Text = "Spire.XLS for JavaScript can wrap text inside a cell in the browser.";
// Turn wrapping on so the text folds inside the cell when it is wider than the column
sheet.Range.get("B2").Style.WrapText = true;
// Turn wrapping off so the text stays on a single line
sheet.Range.get("B3").Style.WrapText = false;
// Narrow column B and raise rows 2-3 so the wrapping is visible
sheet.Range.get("B1:B3").ColumnWidth = 24;
sheet.Range.get("A2:B3").RowHeight = 60;
// Save the workbook
const outputFileName = "WrapText.xlsx";
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Set Text Wrap</h1>
<button onClick={setTextWrap}>Start</button>
</div>
);
}
export default App;
B2 and B3 hold the very same sentence; the only difference is the value of WrapText. B2 folds into several lines and shows in full, while B3 stays on one line. The cell to the right of B3 is empty, so the text spills into it; if there were content there, the overflow would simply be cut off.
After running, the effect of setting the wrapping of text:

FAQ
I set IndentLevel and the text is not indented at all?
Cause: Indentation is only displayed when the horizontal alignment is a non-General value such as Left or Right. Cells default to General alignment, and IndentLevel is ignored outright in that case — so setting only the indent level shows no change.
Solution: Set HorizontalAlignment first, then IndentLevel:
// Indentation only takes effect together with left alignment
sheet.Range.get("B2").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Left;
sheet.Range.get("B3").Style.HorizontalAlignment = xlsModule.HorizontalAlignType.Left;
// Set the indent level of the text
sheet.Range.get("B2").Style.IndentLevel = 1;
sheet.Range.get("B3").Style.IndentLevel = 2;
I want the text stacked vertically, one character per line — why does Rotation = 90 not do it?
Cause: The 0 to 90 and -1 to -90 ranges of Rotation only deal with the rotation angle. 90 merely lays the text on its side; it never breaks it into a column of single characters.
Solution: Stacked text needs the special value 255:
// 90 degrees simply rotates the text
sheet.Range.get("B2").Style.Rotation = 90;
// 255 stacks the text vertically, one character per line
sheet.Range.get("B3").Style.Rotation = 255;
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 Excel, formulas usually have to hard-code a specific cell range, such as =SUM(D2:D10). As such formulas multiply, maintenance costs rise: when the data range changes, every related formula must be updated one by one, and a single missed edit produces a wrong result. A named range is designed to solve exactly this problem — give a cell range a meaningful name and refer to that name in the formula. The range and the formula are thereby separated: changing the range takes a single edit, every formula that refers to it updates automatically, and the result is both less error-prone and easier to read. Spire.XLS for JavaScript ships a complete named range API and can create both global (workbook-level) and local (worksheet-level) named ranges in the browser through WebAssembly, with no backend service required.
This article covers two key features:
For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is already installed and the WebAssembly module has been initialized.
Global Named Range
A global named range is stored in the workbook's name collection Workbook.NameRanges, its name is unique across the whole workbook, and any worksheet can refer to it directly. Create it with Workbook.NameRanges.Add() and point it at a cell range through the RefersToRange property. The steps are:
- Load the Excel file that contains the data and get the first worksheet.
- Create a global named range with
workbook.NameRanges.Add("SalesData"). - Set
namedRange.RefersToRangetosheet.Range.get("A1:D10"), that is, the range A1:D10. - Read
namedRange.NameandnamedRange.RefersToRange.RangeAddressand write the name and the referred address back into cells. - Save the workbook with the
Workbook.SaveToFile()method.
The following is a complete code example that shows how to create a global named range in React:
function App() {
const createGlobalNamedRange = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'NamedRanges.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);
// Create a workbook-level (global) named range
let namedRange = workbook.NameRanges.Add("SalesData");
// Set the cell range the named range refers to
namedRange.RefersToRange = sheet.Range.get("A1:D10");
// Read the name and the referred address
sheet.Range.get("F1").Text = "Named Range Name";
sheet.Range.get("F2").Text = namedRange.Name;
sheet.Range.get("G1").Text = "Refers To Address";
sheet.Range.get("G2").Text = namedRange.RefersToRange.RangeAddress;
// Auto-fit the columns
sheet.AllocatedRange.AutoFitColumns();
// Save the workbook
const outputFileName = 'GlobalNamedRange.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Create Global Named Range</h1>
<button onClick={createGlobalNamedRange}>Start</button>
</div>
);
}
export default App;
After running, the effect of creating a global named range:

Local Named Range
A global named range requires its name to be unique across the entire workbook. When different worksheets all want to use the same name while pointing at different data areas, switch to a local named range instead — added through Worksheet.Names.Add(), its name only takes effect inside the owning worksheet, so same-named ranges can live on several worksheets at once without interfering with each other. The steps are:
- Load the workbook and get the first worksheet.
- Create a local named range on the first worksheet with
sheet.Names.Add("SalesData"), pointing atA2:D10. - Add another worksheet with
workbook.Worksheets.Add()and create a same-named local named range on it, pointing at a different area. - Read the referred address of both ranges back into cells.
- Save the workbook.
The following is a complete code example that shows how to create a local named range in React:
function App() {
const createLocalNamedRange = 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 VFS
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Load the Excel file into VFS
const inputFileName = 'NamedRanges.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);
// Create a local named range on the first worksheet
let localRange = sheet.Names.Add("SalesData");
localRange.RefersToRange = sheet.Range.get("A2:D10");
// Add another worksheet and create a same-named local range on it
let sheet2 = workbook.Worksheets.Add("Summary");
let localRange2 = sheet2.Names.Add("SalesData");
localRange2.RefersToRange = sheet2.Range.get("A1:B5");
// Read the addresses of the same-named ranges in both worksheets
sheet.Range.get("F1").Text = "SalesData on Sheet1";
sheet.Range.get("F2").Text = localRange.RefersToRange.RangeAddress;
sheet.Range.get("G1").Text = "SalesData on Sheet2";
sheet.Range.get("G2").Text = localRange2.RefersToRange.RangeAddress;
// Auto-fit the columns
sheet.AllocatedRange.AutoFitColumns();
// Save the workbook
const outputFileName = 'LocalNamedRange.xlsx';
workbook.SaveToFile(outputFileName);
// Release resources
workbook.Dispose();
// Read the result 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>Create Local Named Range</h1>
<button onClick={createLocalNamedRange}>Start</button>
</div>
);
}
export default App;
After running, the effect of creating a local named range:

FAQ
How do I use a named range in a formula?
Cause: The real value of a named range is being referenced from formulas. Once the amount column is defined as a named range, the formula no longer needs a literal address, and the summed range expands automatically when rows are inserted later.
Solution: Simply write the name of the named range into the formula:
let namedRange = workbook.NameRanges.Add("SalesAmount");
namedRange.RefersToRange = sheet.Range.get("D2:D10");
// Refer to the named range in a formula
sheet.Range.get("F2").Formula = "=SUM(SalesAmount)";
How do I read the named ranges that already exist in a workbook?
Cause: A named range is saved together with the workbook, so it has to be read back before you can tell which names currently exist and which area each one points to.
Solution: Walk the NameRanges collection: take the count first, then read the name and the refers-to address of each entry by index:
// Total number of named ranges
let count = workbook.NameRanges.Count;
// Read the name and the refers-to address of each one
for (let i = 0; i < count; i++) {
let namedRange = workbook.NameRanges.get(i);
sheet.Range.get(`F${i + 2}`).Text = namedRange.Name;
sheet.Range.get(`G${i + 2}`).Text = namedRange.RefersToRange.RangeAddress;
}
This walks workbook-level named ranges; worksheet-level ones are read through sheet.Names, in exactly the same way.
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.