Knowledgebase (2416)
Children categories
Legal Contract Clause Review and Annotation with Spire.Agent.Office
2026-08-17 03:29:50 Written by Nina TangIn corporate legal and compliance management scenarios, contract review is one of the most time-consuming and error-prone tasks. Every contract involves a large number of rights and obligations clauses — liquidated damages, payment terms, disclaimer clauses, breach liability, dispute resolution, and more. Any clause that is unfavorable to your side or ambiguously worded may lead to legal disputes or financial losses in the future. Traditional approaches rely on legal professionals reading and annotating each clause manually; a single contract of dozens of pages often takes hours, and review standards vary from person to person.
Comparison with Traditional SDK API Processing
| Traditional Spire.Office for .NET API | Spire.Agent.Office | |
|---|---|---|
| Driving approach | Write code to parse clauses one by one: load document → iterate paragraphs → regex match keywords → judge risk → highlight and annotate; every step requires code control | Describe the review goal in natural language, and AI automatically identifies and annotates risk clauses |
| Code volume | Requires a large amount of code to maintain the clause risk rule library, keyword matching, and annotation logic | Only configuration code + 1 natural language instruction |
| Risk rules | Risk judgment relies on hard-coded keywords; new risk types require code changes | AI understands clauses semantically and can identify new risks not covered by the rules |
| Review stance | Review logic for each contract type must be developed separately | A single phrase like "review from our side" in the instruction switches the review stance |
| Maintainability | The risk rule library requires continuous manual maintenance | Review scope and rules can be adjusted at any time in natural language |
This article explains how to use the Word AI capability of Spire.Agent.Office to review contract clauses and annotate risks. You can choose to highlight risk clauses on the original contract and add comments, or batch review and output a structured risk review report, meeting contract review needs of different scales and scenarios.
For product installation and SpireToken configuration, refer to Integrating Spire.Agent.Office in a .NET Project. The examples below assume Spire.Agent.Office is installed and SpireToken is configured.
Risk Clause Highlighting and Annotation
Risk clause highlighting and annotation suits in-depth review of important contracts. The core idea is: let AI review contract clauses one by one, identify clauses that are unfavorable to your side or carry legal risks, highlight them in yellow in place and add comments, so legal professionals can view the risk points directly on the contract.
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Doc;
// Path of the contract file to be reviewed
string inputPath = "E:\\Input\\Software_Contract.docx";
// Save path
string savePath = "E:\\Output\\Review.docx";
// Output directory
string OutDir = "E:\\Output";
// SpireToken Key
string key = "xxxxx";
// Natural language instruction
string instruction =
"Review all clauses in the current contract document and identify clauses that are unfavorable to the purchaser or carry legal risks, including but not limited to: " +
"excessively high liquidated damages, stringent payment terms, overly broad disclaimer clauses, missing breach liability provisions, unfavorable court jurisdiction agreements, unclear intellectual property ownership, etc. " +
"For each risk clause, perform the following operations: 1. Highlight the risk clause text in yellow; 2. Add a comment in place, noting the risk point, risk level (high/medium/low), and modification suggestions. " +
"After processing, keep the same layout, styles, and fonts as the original document, and finally save and output in DOCX format";
// Call the Word document processing function
AIResult result = ExecuteDemoWord(instruction, inputPath, savePath, key, OutDir, null);
// Execute Word document AI processing
static AIResult ExecuteDemoWord(string instruction, string inputPath, string savePath, string key, string output, string[] attachmentPaths)
{
// Create an AIOptions configuration object
AIOptions options = new AIOptions();
// Set the working directory to the output directory
options.WorkDir = output;
// Set the SpireToken Key
options.SpireToken = key;
// Use the Document object to process the Word document
using (Document doc = new Document())
{
// Load the contract document from file
if (!string.IsNullOrEmpty(inputPath) && File.Exists(inputPath))
{
doc.LoadFromFile(inputPath);
}
// Create the AI document processor
AIDocumentProcessor processor = doc.AI(options);
// Execute the AI instruction
return processor.ExecuteInstruction(doc, instruction, savePath, attachmentPaths);
}
}
Contract after AI highlighting and annotation 
In the reviewed contract, risk clauses are highlighted in yellow, and the comments clearly state the risk points and modification suggestions. Legal professionals can quickly locate the highlighted positions without reading the original text line by line, and can directly discuss modification plans with the business side based on the comments.
Batch Review and Review Report
For quick screening of large batches of contracts (such as contract renewal or supplier qualification review), batch review with a structured review report is more suitable. The core idea is: let AI review multiple contracts one by one, consolidate the risk clauses of each contract into a risk list, and output it as an MD report for statistics, tracking, and tiered processing.
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Doc;
// Paths of multiple contract files to be reviewed
string[] attachments = new string[] {
"E:\\Input\\Purchase_Contract_EN.docx", // Purchase contract
"E:\\Input\\Sales_Contract_EN.docx", // Sales contract
"E:\\Input\\Labor_Contract_EN.docx" // Labor contract
};
// Save path (null here; the output folder path set below will be used)
string savePath = "E:\\Output\\Structural_Review_Output.md";
// Output directory
string OutDir = "E:\\Output";
// SpireToken Key
string key = "xxxxx";
// Natural language instruction
string instruction =
"Review the contract documents in the attachments one by one, extract risk clauses, and output a Markdown review report: " +
"The report contains a table with fixed columns: Contract Name | Clause Number | Clause Original Text | Risk Level (High/Medium/Low) | Risk Type | Risk Description | Modification Suggestion. " +
"Sort by risk level from high to low; the clause original text must be quoted from the contract, truncated with … after 20 characters, and must not be fabricated.";
// Call the Word document processing function
AIResult result = ExecuteDemoWord(instruction, savePath, key, OutDir, attachments);
// Execute Word document AI processing
static AIResult ExecuteDemoWord(string instruction, string savePath, string key, string output, string[] attachments)
{
// Create an AIOptions configuration object
AIOptions options = new AIOptions();
// Set the working directory to the output directory
options.WorkDir = output;
// Set the SpireToken Key
options.SpireToken = key;
// Use the Document object to process the Word document
using (Document doc = new Document())
{
// Create the AI document processor
AIDocumentProcessor processor = doc.AI(options);
// Execute the AI instruction
return processor.ExecuteInstruction(doc, instruction, savePath, attachments);
}
}
Contract risk review report output by AI 
Each row in the review report corresponds to a risk clause and contains the clause original text, risk level, risk type, and modification suggestion. Legal professionals can sort by risk level to prioritize high-risk clauses, or export the report for risk ledger tracking in a contract management system.
FAQ
Risk clauses identified inaccurately
Reason: AI's judgment of "unfavorable clauses" depends on the review stance. From your side's perspective versus the counterparty's perspective, the risk judgment for the same clause may be completely opposite.
Solution: Specify the review stance clearly in the instruction, such as "review from the purchaser's perspective", and add a list of risk types to focus on. AI will strictly follow this stance and scope.
Document style changes after highlighting
Reason: The AI model automatically modified or added content during processing.
Solution: Add a description such as "keep the same layout, styles, and fonts as the original document" to the instruction.
Review report does not accurately correspond to contract clauses
Reason: Clause numbers are inconsistent, or the same clause is scattered across multiple places in the contract, causing the clause original text in the report to not match the contract.
Solution: In the instruction, require AI to quote the clause original text and note the source of the clause number, for easy manual verification and location.
Get the SpireToken Key
- Contact sales@e-iceblue.com or visit https://www.e-iceblue.com/TemLicense.html to obtain a trial/commercial API key
Configure it in your code:
AIOptions options = new AIOptions();
options.SpireToken = key;
Reconciliation is one of the most frequent and tedious tasks in corporate finance, and the source data often comes in different forms: bank statements are CSV files exported from online banking, while system transaction records may be PDF detail reports. The two tables have different column names, inconsistent date and amount formats, and even stray spaces and missing values. This article shows how to use Spire.Agent.Office Excel AI capabilities to automatically read CSV and PDF data sources, identify and map column names, clean the data, and finally generate an Excel reconciliation detail report.
For product installation and SpireToken configuration, please refer to Integrate Spire.Agent.Office in a .NET Project. The following examples assume Spire.Agent.Office is installed and SpireToken is configured.
Reconcile by Statement Number
Reconcile and analyze the CSV-format bank statement with the PDF-format system transaction records by statement number.
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Xls;
// Data source files: bank statement (CSV) and system transaction records (PDF)
string[] attachmentPaths = new string[]
{
@"bank-statement.csv",
@"system-records.pdf"
};
// Excel processing configuration
string inputPath = "";
string savePath = "out.xlsx";
// SpireToken Key
string key = "**************************";
string instruction =
"Reconcile the bank statement (CSV) with the system transaction records (PDF) in the attachments: " +
"1. Establish the column mapping of the two tables by semantics: transaction date, amount, counterparty account, description, statement number; " +
"2. Cleaning: strip leading/trailing and internal extra spaces from text; write dates as yyyy-MM-dd text; convert amounts to numbers by removing currency symbols and thousands separators; mark empty description or empty counterparty as 'Unknown', mark empty amount as 'Amount missing'; " +
"3. Match row by row using the statement number as the unique key, and mark the status: 'Matched'/'Amount mismatch'/'Bank only'/'System only'; " +
"4. Generate a 'Reconciliation Detail' worksheet: each record with bank amount, system amount, difference, status and remark; " +
"5. Highlight difference rows: yellow for amount mismatch, orange for bank only, blue for system only; " +
"Finally save the output as an Excel file";
// Call the Excel document processing function
AIResult result = ExecuteDemoExcel(instruction, inputPath, savePath, key, attachmentPaths);
// Execute Excel document AI processing
static AIResult ExecuteDemoExcel(string instruction, string inputPath, string savePath, string key, string[] attachmentPaths)
{
// Create an AIOptions configuration object
AIOptions options = new AIOptions();
options.SpireToken = key;
// Use the Workbook object to process the Excel document
using (Workbook workbook = new Workbook())
{
// Load the Excel template from a file
if (!string.IsNullOrEmpty(inputPath) && File.Exists(inputPath))
{
workbook.LoadFromFile(inputPath);
}
// Create the AI document processor
AIWorkbookProcessor processor = workbook.AI(options);
// Execute the AI instruction
return processor.ExecuteInstruction(workbook, instruction, savePath, attachmentPaths);
}
}
Original bank statement CSV
Original system transaction PDF
Reconciliation detail after Excel AI reconciliation 
Reconcile by Date and Amount Combination
When the data source does not contain a unique statement number, you can use the "transaction date + amount" combination as the matching key for reconciliation: first group by date, then pair the records by amount within the same date.
using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;
using Spire.Xls;
// Data source files without statement numbers: bank statement (CSV) and system transaction records (PDF)
string[] attachmentPaths = new string[]
{
@"bank-statement-noId.csv",
@"system-records-noId.pdf"
};
// Excel processing configuration
string inputPath = "";
string savePath = "out.xlsx";
// SpireToken Key
string key = "**************************";
string instruction =
"Reconcile the bank statement (CSV) with the system transaction records (PDF) in the attachments: " +
"1. Establish the column mapping of the two tables by semantics: transaction date, amount, counterparty account, description; " +
"2. Cleaning: strip extra spaces from text; write dates as yyyy-MM-dd text; convert amounts to numbers; mark missing values as 'Unknown' or 'Amount missing'; " +
"3. Use the 'transaction date + amount' combination as the matching key: first group by date, then pair the records by amount within the same date, and mark the status: 'Matched'/'Amount mismatch'/'Bank only'/'System only'; " +
"4. Generate a 'Reconciliation Detail' worksheet (bank amount, system amount, difference, status); " +
"5. Highlight difference rows: yellow for amount mismatch, orange for bank only, blue for system only; " +
"Finally save the output as an Excel file";
// Call the Excel document processing function
AIResult result = ExecuteDemoExcel(instruction, inputPath, savePath, key, attachmentPaths);
// Execute Excel document AI processing
static AIResult ExecuteDemoExcel(string instruction, string inputPath, string savePath, string key, string[] attachmentPaths)
{
// Create an AIOptions configuration object
AIOptions options = new AIOptions();
options.SpireToken = key;
// Use the Workbook object to process the Excel document
using (Workbook workbook = new Workbook())
{
// Load the Excel template from a file
if (!string.IsNullOrEmpty(inputPath) && File.Exists(inputPath))
{
workbook.LoadFromFile(inputPath);
}
// Create the AI document processor
AIWorkbookProcessor processor = workbook.AI(options);
// Execute the AI instruction
return processor.ExecuteInstruction(workbook, instruction, savePath, attachmentPaths);
}
}
Original bank statement CSV
Original system transaction PDF
Reconciliation detail after Excel AI reconciliation 
Comparison with Traditional SDK API Processing
| Traditional Spire.Office for .NET API | Spire.Agent.Office Processing | |
|---|---|---|
| Driving approach | Requires writing large amounts of code for CSV/PDF parsing, column mapping, data cleaning, matching and exception logic | Describe reconciliation rules in natural language, and AI understands and orchestrates the execution automatically |
| Data format | CSV and PDF must be parsed with different components, each with its own format | Directly attach CSV and PDF, and AI understands the content automatically |
| Field mapping | Hard-coded column name mappings; changing column names or formats requires code changes | AI maps columns automatically based on column names and content semantics |
| Exception handling | Need to hand-write difference judgment, alert text and style logic | AI automatically identifies differences and provides handling suggestions |
Frequently Asked Questions
Inconsistent date and amount formats in the bank statement CSV
Cause: In the CSV exported from online banking, dates may be written as 2026-07-01, 2026/7/1, etc., and amounts may carry ¥, thousands separators, or leading/trailing spaces, leading to misjudgment during matching.
Solution: Explicitly require in the instruction "unify dates as yyyy-MM-dd and amounts as numeric formats and remove spaces", and AI will complete the standardization automatically before reconciliation.
The system transaction PDF table spans pages or has headers/footers
Cause: PDF detail reports may have pagination, repeated headers, or footer annotations, which affect AI's reading of the table data.
Solution: Add "ignore headers/footers and repeated header rows, only read the table data rows" to the instruction.
The same amount appears multiple times on the same day, causing mismatches
Cause: When reconciling by the "date + amount" combination, there may be multiple transactions with the same amount on the same day, making the exact correspondence impossible to determine.
Solution: Prefer precise reconciliation by statement number; if there is really no statement number, you can require in the instruction to "mark records that cannot be matched one-to-one on the same day as 'Amount mismatch'".
Get a SpireToken Key
- Contact sales@e-iceblue.com or visit https://www.e-iceblue.com/TemLicense.html to obtain a trial/commercial API key
Configure it in code:
AIOptions options = new AIOptions();
options.SpireToken = key;
Create and Save Excel Files through Streams with JavaScript in React
2026-08-14 08:13:24 Written by jie zouOperating Excel files as streams in web applications allows developers to dynamically create, load, modify, and save Excel files, enabling flexible and efficient data processing. Spire.XLS for JavaScript runs entirely in the browser via WebAssembly, using a virtual file system (VFS) to manage input and output files — no backend server is required. It provides a simple, easy-to-use Stream API that makes creating and saving Excel files through streams more convenient.
Working with streams greatly reduces direct disk I/O operations, improving application performance and responsiveness, especially in scenarios that involve real-time data processing or limited storage. With Spire.XLS for JavaScript, you can dynamically create an Excel file and save it to a stream, load and read workbook data from a stream, or modify content in a stream and save it as a new Excel file — all directly in the browser, simplifying data exchange and system integration.
This article covers three core features:
- Dynamically Create an Excel File and Save It to a Stream
- Load and Read an Excel File from a Stream
- Modify and Save an Excel File in a Stream
For installation and project setup, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Dynamically Create an Excel File and Save It to a Stream
With Spire.XLS for JavaScript, you can dynamically create an Excel file in the browser, fill it with data and formatting, and then save the workbook to a file stream via the SaveToStream() method. This approach eliminates the need to store files directly on disk while improving application performance and responsiveness. The steps are as follows:
- Create a
Workbookinstance to generate a new Excel workbook, clear the default worksheets, and add a new worksheet. - Access a specific worksheet using the
Worksheets.get()method. - Define the data to write to the worksheet, for example, organizing data with a two-dimensional array.
- Use the
Range.get_Item()method to access cells and set their values one by one. - Format the worksheet cells, such as setting colors, fonts, borders, or adjusting column widths.
- Create a
Streamobject and save the workbook to the file stream using theSaveToStream()method. The saved stream can be used for further processing, such as downloading as a file or transferring over the network.
Below is a complete code example demonstrating how to dynamically create an Excel file and save it to a stream in React:
function App() {
const createAndSaveToStream = 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 file to ensure proper text rendering
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}font/`);
// Create a new workbook instance
const workbook = new xlsModule.Workbook();
// Clear the default worksheets and add a new worksheet
workbook.Worksheets.Clear();
const sheet = workbook.Worksheets.Add('Data');
// Define the sample data to write to the worksheet (two-dimensional array)
const headers = ['ID', 'Name', 'Age', 'Country', 'Salary (¥)'];
const data = [
[1, 'Zhang Wei', 29, 'China', 8000],
[2, 'Li Na', 35, 'China', 12000],
[3, 'Wang Qiang', 42, 'China', 15000],
[4, 'Jack', 26, 'USA', 9500],
[5, 'Chen Si', 31, 'China', 11000],
[6, 'Ishihara Yasuko', 28, 'Japan', 8800]
];
// Write the headers to the first row
for (let col = 0; col < headers.length; col++) {
sheet.Range.get_Item({ row: 1, column: col + 1 }).Text = headers[col];
}
// Write the data to the following rows
for (let row = 0; row < data.length; row++) {
for (let col = 0; col < data[row].length; col++) {
sheet.Range.get_Item({ row: row + 2, column: col + 1 }).Text = String(data[row][col]);
}
}
// Format the header row
sheet.Range.get('A1:E1').Style.Color = xlsModule.Color.get_LightSkyBlue();
sheet.Range.get('A1:E1').Style.Font.FontName = 'Arial';
sheet.Range.get('A1:E1').Style.Font.Size = 12;
sheet.Range.get('A1:E1').Style.Font.IsBold = true;
// Format the data rows
for (let i = 2; i <= data.length + 1; i++) {
const dataRange = sheet.Range.get({
row: i, column: 1,
lastRow: i, lastColumn: headers.length
});
dataRange.Style.Color = xlsModule.Color.get_LightGray();
dataRange.Style.Font.FontName = 'Arial';
dataRange.Style.Font.Size = 11;
}
// Add borders to the header and all data cells
const usedRange = sheet.Range.get({
row: 1, column: 1,
lastRow: data.length + 1,
lastColumn: headers.length
});
usedRange.Borders.LineStyle = xlsModule.LineStyleType.Thin;
usedRange.Borders.Color = xlsModule.Color.get_LightSteelBlue();
// Adjust column widths to fit the content
for (let col = 1; col <= headers.length; col++) {
sheet.AutoFitColumn(col);
}
// Create a stream and save the workbook to it
const outputFileName = 'CreateExcelToStream.xlsx';
const fileStream = new xlsModule.Stream(outputFileName);
workbook.SaveToStream(fileStream, xlsModule.FileFormat.Version2010);
// Dispose of the workbook object to release resources
workbook.Dispose();
// Read the file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Create Excel and Save to Stream</h1>
<button onClick={createAndSaveToStream}>
Generate
</button>
</div>
);
}
export default App;
Excel file dynamically created and saved to a stream with Spire.XLS for JavaScript

Load and Read an Excel File from a Stream
With Spire.XLS for JavaScript, you can load an Excel file directly from a stream using the LoadFromStream() method. Once loaded, the cell data of the Excel file in the stream can be easily read, enabling fast and flexible data processing without file I/O operations. The steps are as follows:
- Create a
Streamobject pointing to the Excel file to be loaded. - Create a
Workbookobject and load the file from the stream using theLoadFromStream()method. - Get the first worksheet using the
Worksheets.get()method. - Iterate through the rows and columns of the worksheet and extract cell data using the
Range.get()method. - Display the extracted data on the page, or use it for other operations.
Below is a complete code example demonstrating how to load and read an Excel file from a stream in React:
import React, { useState } from 'react';
function App() {
const [extractedData, setExtractedData] = useState('');
const loadAndReadFromStream = 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 file to ensure proper text rendering
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}font/`);
// Load the sample Excel file into VFS
await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);
// Create a workbook object and load the Excel file from a stream
const workbook = new xlsModule.Workbook();
const fileStream = new xlsModule.Stream('Sample.xlsx');
workbook.LoadFromStream(fileStream, xlsModule.FileFormat.Auto);
// Get the first worksheet of the workbook
const sheet = workbook.Worksheets.get(0);
// Iterate through the rows and columns to extract cell data
const data = [];
for (let row = sheet.FirstRow; row <= sheet.LastRow; row++) {
const line = [];
for (let col = sheet.FirstColumn; col <= sheet.LastColumn; col++) {
line.push(sheet.Range.get({ row: row, column: col }).Text);
}
data.push(line.join(' | '));
}
// Dispose of the workbook object to release resources
workbook.Dispose();
// Display the extracted data on the page
setExtractedData(data.join('\n'));
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Load and Read Excel Data from Stream</h1>
<button onClick={loadAndReadFromStream}>
Read
</button>
<pre style={{ marginTop: '20px', textAlign: 'left' }}>{extractedData}</pre>
</div>
);
}
export default App;
Excel file loaded and read from a stream with Spire.XLS for JavaScript

Modify and Save an Excel File in a Stream
With Spire.XLS for JavaScript, you can modify an Excel file in memory. First load the Excel file in the stream into a Workbook object via the LoadFromStream() method; after completing modifications such as changing cell styles or content, save the file back to a stream using the SaveToStream() method. This enables real-time changes to Excel file data without relying on direct file storage operations. The steps are as follows:
- Create a
Streamobject pointing to the Excel file and load the file from the stream via theLoadFromStream()method. - Access the worksheet using the
Worksheets.get()method. - Modify the styles of the header row and data rows (font name, size, background color, etc.) through the
CellRange.Styleproperty. - Use the
AutoFitColumn()method to automatically adjust column widths to fit the content. - Set the border style of the cells.
- Create a new
Streamobject, save the modified workbook to the stream using theSaveToStream()method, read the result file from VFS, and trigger the download.
Below is a complete code example demonstrating how to modify and save an Excel file in a stream in React:
function App() {
const modifyAndSaveInStream = 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 file to ensure proper text rendering
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}font/`);
// Load the sample Excel file into VFS
await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);
// Create a workbook object and load the Excel file from a stream
const workbook = new xlsModule.Workbook();
const fileStream = new xlsModule.Stream('Sample.xlsx');
workbook.LoadFromStream(fileStream, xlsModule.FileFormat.Auto);
// Get the first worksheet of the workbook
const sheet = workbook.Worksheets.get(0);
// Modify the style of the header row
const headerRow = sheet.Range.get({
row: sheet.FirstRow, column: sheet.FirstColumn,
lastRow: sheet.FirstRow, lastColumn: sheet.LastColumn
});
headerRow.Style.Font.FontName = 'Arial';
headerRow.Style.Font.Size = 12;
headerRow.Style.Font.IsBold = true;
headerRow.Style.Color = xlsModule.Color.get_LightSkyBlue();
// Modify the styles of the data rows, with alternating colors (even rows)
for (let i = sheet.FirstRow + 1; i <= sheet.LastRow; i++) {
const dataRow = sheet.Range.get({
row: i, column: sheet.FirstColumn,
lastRow: i, lastColumn: sheet.LastColumn
});
dataRow.Style.Font.FontName = 'Arial';
dataRow.Style.Font.Size = 10;
dataRow.Style.Color = xlsModule.Color.get_LightGray();
if (i % 2 === 0) {
dataRow.Style.Color = xlsModule.Color.get_DarkGray();
}
}
// Adjust column widths to fit the content
for (let col = sheet.FirstColumn; col <= sheet.LastColumn; col++) {
sheet.AutoFitColumn(col);
}
// Set the border color
sheet.AllocatedRange.Borders.Color = xlsModule.Color.get_White();
// Save the modified workbook to a new stream
const outputFileName = 'ModifyExcelInStream.xlsx';
const outStream = new xlsModule.Stream(outputFileName);
workbook.SaveToStream(outStream, xlsModule.FileFormat.Version2010);
// Dispose of the workbook object to release resources
workbook.Dispose();
// Read the file from VFS and trigger download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Modify and Save Excel in Stream</h1>
<button onClick={modifyAndSaveInStream}>
Generate
</button>
</div>
);
}
export default App;
Excel file modified and saved in a stream with Spire.XLS for JavaScript

FAQ
How to handle the stream-saved file being unable to open in Excel?
Cause: When saving a workbook via the SaveToStream() method, if the correct output file format is not specified through the FileFormat parameter, the generated file format may not match its extension, causing it to fail to open properly.
Solution: Specify a concrete file format enum value when saving to a stream, such as xlsModule.FileFormat.Version2010:
const fileStream = new xlsModule.Stream(outputFileName);
workbook.SaveToStream(fileStream, xlsModule.FileFormat.Version2010);
How to ensure the workbook loaded from a stream correctly recognizes the file format?
Cause: The LoadFromStream() method needs to identify the file type based on the actual format of the stream data. If the format parameter is set incorrectly, loading may fail or data parsing may produce errors.
Solution: Use xlsModule.FileFormat.Auto when loading so that the library automatically detects the format of the file in the stream:
const fileStream = new xlsModule.Stream('Sample.xlsx');
workbook.LoadFromStream(fileStream, xlsModule.FileFormat.Auto);
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.