Knowledgebase (2595)
Children categories
Co-editing lets multiple users open the same document at the same time, with everyone's changes visible to everyone else, without sending files back and forth or merging manually. Spire.OfficeJS has co-editing built in: with the right page configuration, two browser tabs or two users can join the same editing session. This article uses Word as an example. It first explains how co-editing works and what it requires, then walks through the key configuration piece by piece, and finally gives a complete runnable example.
How Co-editing Works
The following diagram and steps explain how co-editing works in Spire.OfficeJS.

- User 1 and User 2 open the document with the same co-editing identifier (that is, the same
fileInfo.primary). - User 1 edits the document.
- The editor reports the changes to the co-authoring service (the service that
coAuthorUrlpoints to). - The co-authoring service distributes the changes to User 2's editor.
- User 2's editor applies the changes, so the same content appears on both screens.
The key point: the same co-editing session must use the same primary. In addition, you need to connect to an Office Server (see Prerequisites for Co-editing); everything else is configuration and state management built around these two things.
Many people assume when they first encounter online editing that the browser edits the Word file on the server directly. That is not the case. Spire.OfficeJS edits an internal cached editing file (Editor.bin), not the original Word file:

Prerequisites for Co-editing
Co-editing does not "just work" once you embed the editor in a page. For two users to join the same co-editing session and see each other's changes, two conditions must both hold:
- The same primary:
fileInfo.primaryis not an ordinary "file ID" but the identity of the current co-editing version. Make surefileInfo.primaryis the same (for how it works and how it is generated, see The Co-editing Identifier: fileInfo.primary). - Connect to an Office Server: the editor needs to connect to an Office Server (either locally started or remotely deployed) and use
coAuthorUrlto specify its address (see The Co-authoring Service Address: coAuthorUrl).
Both are required: with different primary values you get two separate sessions. Without a co-authoring service, changes have no channel to be distributed through.
The simplest way to verify: open the page in two tabs using the same fileInfo.primary but different user.id values. As long as primary matches, they join the same co-editing session — effectively "co-editing with yourself".
Tip
If you want some people to take part in co-editing in read-only mode, set their editorAttrs.canEdit to false. In fast mode they can still see other people's changes in real time but cannot edit, which suits observation, demonstration, or approval scenarios.
The Co-editing Identifier: fileInfo.primary
fileInfo.primary is the sole basis on which Spire.OfficeJS decides "is this the same document being co-edited?" All participants must use the same value to join the same co-editing session.
Generation and Reuse
- It must be supplied explicitly by the page and stay stable for the same session. If left empty, Spire.OfficeJS generates a random one, and each user gets a different value every time they open the page, so the sessions end up independent and unsynchronized.
- Character set: a randomly generated value consists of lowercase letters and digits and is about 20 characters long.
- Do not reuse: one "editing session" of a document corresponds to one
primary; a new round of editing should use a new value.
After a save completes, it is recommended to use a new primary the next time the document is opened: this isolates the "saved content" from "a new round of co-editing" and keeps the cache, version, and new changes of the previous session from mixing together. If you keep reusing an old value for repeated editing, content rollbacks or synchronization anomalies are easy to run into.
When you rotate primary, also point sourceUrl at the file saved in this round (usually the file address obtained from onSave). Otherwise, the first open with the new primary re-downloads and converts the old original file, and the content you just saved is lost.
Fast Mode and Strict Mode
Spire.OfficeJS provides two co-editing modes: fast mode and strict mode. You switch between them in the UI via "Review → Editing Mode" or "File → Advanced Settings → Co-editing Mode". Both let multiple people join the same session; the difference is when changes are synchronized and who triggers the save: fast mode syncs as you edit, while strict mode lets everyone edit their own copy and merges only on save.
Fast Mode (Default)
In fast mode, anyone's changes are broadcast to all participants in real time: text, cursor position, and selections are immediately visible with no need to save. Before editing a region (a paragraph, a cell, etc.), the editor first acquires a block lock on that region; others see the region as occupied until editing finishes or the lock is released.

Strict Mode
In strict mode, everyone edits in their own isolated copy but still belongs to the same co-editing session: other people's changes stay hidden until saved, and regions edited by multiple people at the same time are marked with dashed lines in different colors. Only after you click "Save" is the whole document submitted to the co-authoring service for merging.

Comparison of the Two Modes
| Dimension | Fast Mode (Default) | Strict Mode |
|---|---|---|
| Change visibility | Broadcast in real time; other people's cursors and changes are immediately visible | Isolated; neither side sees the other's changes before saving |
| Saving | Automatic sync (no manual save needed) | Syncs only after you click "Save" manually |
| Undo / Redo | Unavailable | Available |
| Notification of others' changes | None (already seen in real time) | Click Save and reload |
| Suitable for | Multiple people making small, high-frequency collaborative edits | Large edits, isolated review, concerns about accidental overwrites |
Configuring the Default Mode
Controlled by two switches under user.customization.public.common:
user: {
customization: {
public: {
common: {
CollaborationModeIsFast: true, // Enter fast mode on open
CollaborationModeOnlyFast: false
}
}
}
}
CollaborationModeIsFast: the initial mode when the document opens.truemeans fast mode,falsemeans strict mode. Fast mode is the default.CollaborationModeOnlyFast: when set totrue, locks fast mode; the strict option in "Co-editing Mode" is disabled and users cannot switch to strict mode. Suits scenarios that require everyone to always share changes in real time.
The Co-authoring Service Address: coAuthorUrl
coAuthorUrl points to the editor service that provides co-authoring capability (the Office Server) and must be configured explicitly. It is configured under editorAttrs.serverless; an example:
editorAttrs: {
useWebAssemblyDoc: true,
serverless: {
useServerless: true,
baseUrl: 'https://LocalExample:3000', // Address of the front-end resources (web directory)
coAuthorUrl: 'https://LocalExample:8000' // Co-authoring service (Office Server) address
}
}
Note the distinction between the three kinds of addresses: the load address of SpireCloudEditor.js and baseUrl only determine where the front-end resources are loaded from; they are not the co-authoring service address. coAuthorUrl must point to an Office Server reachable by the browser; otherwise co-editing cannot work either.
Quick Start: Two People Editing the Same Document
This section assembles the preceding content into a minimal runnable page: just replace the script address, service address, document address, user information, and save handling.
Page Structure
Place a container div on the page, then include the Spire.OfficeJS editor script:
<div id="editor"></div>
<!-- The editor script is served by your Spire.OfficeJS service -->
<script src="https://LocalExample:3000/web/editors/spireapi/SpireCloudEditor.js"></script>
Initialization Configuration
<script>
// Co-editing session primary: same document, same co-editing session — must be identical for all users
const DOC_PRIMARY = 'a1b2c3d4e5f6g7h8i9j0';
// Current user: id must be unique and stable; name is the display name during collaboration
const currentUser = {
id: 'user-1001',
name: 'John Doe'
};
const config = {
fileAttrs: {
fileInfo: {
name: 'project-plan.docx',
ext: 'docx',
primary: DOC_PRIMARY // Co-editing session primary
},
sourceUrl: 'https://your-file-host/files/project-plan.docx'
},
user: {
id: currentUser.id,
name: currentUser.name,
customization: {
public: {
common: {
CollaborationModeIsFast: true, // Enter fast mode on open
CollaborationModeOnlyFast: false
}
}
}
},
editorAttrs: {
useWebAssemblyDoc: true,
serverless: {
useServerless: true,
baseUrl: 'https://LocalExample:3000', // Address of the front-end resources (web directory)
coAuthorUrl: 'https://LocalExample:8000' // Co-authoring service (Office Server) address
},
editorMode: 'edit',
editorType: 'document',
editorWidth: '100%',
editorHeight: '800px',
viewLanguage: 'zh',
canEdit: true,
canReview: true,
canComment: true,
canChat: true,
events: {
// Handle the save in the page: event.data[1] is the File object of the current document
onSave: function (event) {
const fileName = event.data[0];
const file = event.data[1];
const form = new FormData();
form.append('file', file, fileName);
form.append('primary', DOC_PRIMARY);
fetch('https://your-file-host/save-file', {
method: 'POST',
body: form
});
}
}
}
};
new SpireCloudEditor.OpenApi('editor', config);
</script>
FAQ
Both Users Open the Page but Changes Do Not Sync
Troubleshoot in this order:
- Whether
fileAttrs.fileInfo.primaryis the same. Differentprimaryvalues lead to two independent sessions; even ifsourceUrlis exactly the same, they will not sync. - Whether an Office Server is configured and connected.
editorAttrs.serverless.coAuthorUrlmust point to an Office Server reachable by the browser: either started locally (for examplehttp://127.0.0.1:8000) or deployed remotely. If it is missing or misconfigured, co-editing fails (see The Co-authoring Service Address: coAuthorUrl). sourceUrlonly takes effect on the first open or a cache miss. Once the sameprimaryhits the cache, it is no longer read. To switch files, updatesourceUrland use a newprimaryat the same time.
The "Co-editing Mode" Entry Is Missing
The entry requires editorMode: 'edit'.
Cannot Undo / Redo in Fast Mode
This is by design in fast mode: changes are broadcast in real time and synced automatically, so they cannot be rolled back from a single client. If you need an undo history, switch to strict mode, edit in the isolated copy, and then save.
Co-editing Breaks or Content Rolls Back After Saving
It is most likely that an old primary was reused. After a save completes (onSave has received the file), the next time you open the document you should use a new primary and point sourceUrl at the saved file; do not keep using the old value of a completed save for a new session.
On a business page, users open the editor to edit a document and then need to close it. Many pages simply remove the editor from the page when the user closes it. The editor is no longer visible, but some of its listeners are still running in the background. If the editor is opened and closed repeatedly, the old listeners may still respond to operations on the new document, and the page becomes slower. When the editor is no longer needed, clean it up with destroyEditor(). This article uses Word as an example to explain how to destroy a Spire.OfficeJS editor.
Destroy process
Destroying the editor can be summarized in three steps: open the editor, call destroyEditor(), and restore the page to its original state.

- The user opens the editor.
OpenApicreates the editor on the business page, and the original placeholder<div>is replaced. - Call
destroyEditor()to remove the editor. It unbinds themessagelistener and themouseuplistener on the business page, then replaces the editor iframe with the original placeholder<div>. - The page returns to its state before opening, and the placeholder
<div>appears again.
How to call it
destroyEditor() is not a global method, nor is it on the editor iframe element. It is a method on the object returned by new SpireCloudEditor.OpenApi(). Save the returned object when you create the editor, and call the method on that object when you destroy the editor.
Example code:
var editor = new SpireCloudEditor.OpenApi('editor', config);
editor.destroyEditor();
editor = null;
Note
Call destroyEditor() only once per editor instance; calling it again on the same instance throws an error. After a successful destroy, set editor to null to avoid using the stale object. To open the editor again, create a new instance.
Complete example
Below is a complete example: the page creates the editor and saves the returned object when the page loads, then calls destroyEditor() when the user clicks the "Destroy Editor" button. Replace LocalExample:3000 with the actual deployment address before running.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Spire.OfficeJS Destroy Editor</title>
<style>
html, body { height: 100%; margin: 0; background-color: #cbe4f3;}
body { display: flex; flex-direction: column; }
#editor { flex: 1; min-height: 0; }
#editor iframe { width: 100%; height: 100%; border: 0; }
</style>
</head>
<body>
<button id="destroyBtn">Destroy Editor</button>
<div id="editor"></div>
<script src="http://LocalExample:3000/web/editors/spireapi/SpireCloudEditor.js"></script>
<script>
var SERVER = 'http://LocalExample:3000';
var config = {
fileAttrs: {
fileInfo: { name: 'sample.docx', ext: 'docx' },
sourceUrl: SERVER + '/samples/sample.docx'
},
user: { id: 'uid-1', name: 'Jonn' },
editorAttrs: {
editorMode: 'edit',
editorType: 'document',
viewLanguage: 'en',
useWebAssemblyDoc: true,
spireOfficeJsLicense: '',
serverless: {
useServerless: true,
baseUrl: SERVER
}
}
};
var editor = new SpireCloudEditor.OpenApi('editor', config);
document.getElementById('destroyBtn').addEventListener('click', function () {
editor.destroyEditor();
editor = null;
});
</script>
</body>
</html>
After you open the document and click the "Destroy Editor" button, the editor is destroyed:

Note
destroyEditor() does not save the document and does not cancel save or download requests that have already been sent. If you need to keep changes, save first and wait for the save to complete before destroying the editor.
FAQ
The container style changes after destroying the editor
Cause: The placeholder <div> restored by destroyEditor() has only its id set; its original class and inline style are not restored.
Solution: Put the container's size and styles in an ID selector, for example #editor { flex: 1; min-height: 0; }.
Can I still use methods such as downloadAs after calling destroyEditor()?
Cause: destroyEditor() unbinds the listeners on the business page, so the returned object no longer receives responses from the editor.
Solution: Do not use other methods on the returned object after calling destroyEditor().
Does destroyEditor() clear localStorage or the server-side cache?
Cause: destroyEditor() only performs cleanup on the business page; it does not clear browser storage or the server-side cache.
Solution: If cleanup is needed, handle it separately in the business system.
Numbers stored in Excel cells often need to be displayed in different formats, such as keeping two decimal places, adding thousands separators, displaying amounts as currency, highlighting negative numbers in red, or showing them as percentages or in scientific notation. Proper number formatting not only makes reports easier to read but also avoids errors caused by manual entry and layout. Spire.XLS for JavaScript completes this directly in the browser based on WebAssembly, and manages input/output files through a virtual file system (VFS), with no backend service required.
Spire.XLS for JavaScript sets number formats through the NumberFormat property of the cell range Range. NumberFormat accepts Excel-standard format code strings. The table below lists the commonly used format code symbols and their meanings:
| Symbol | Description |
|---|---|
0 |
Digit placeholder that always displays a digit, padding with 0 when there are not enough digits |
# |
Digit placeholder that shows only significant digits; extra zeros are not displayed |
? |
Digit placeholder that leaves space for insignificant zeros, used to align decimal points |
. |
Decimal point |
, |
Thousands separator |
% |
Multiplies the number by 100 and displays it as a percentage |
E+ / E- |
Exponent part of scientific notation |
; |
Separates the formats for positive numbers, negative numbers, zeros and text |
[Red] and other color codes |
Sets the display color of the number, e.g. [Red], [Blue], [Green] |
[DBNum1] / [DBNum2] |
Converts numbers to Chinese lowercase / uppercase numerals |
@ |
Text placeholder that displays the number as text |
This article covers three core features:
- Set Decimal Places and Thousands Separator
- Set Currency Format and Highlight Negative Values
- Set Percentage, Scientific Notation and Other Formats
For installation and project configuration, refer to Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module is initialized.
Set Decimal Places and Thousands Separator
When processing amounts, statistics and other data, it is often necessary to keep numbers to a specified number of decimal places, or to add thousands separators for readability. Presenting the same values with the right format codes makes reports easier to scan and avoids manual padding or misplaced commas.
The steps are:
- Load the font file into the VFS for text measurement.
- Create a
Workbookobject and get the first worksheet withWorkbook.Worksheets.get(0). - Use the
Range.Textproperty to write the title, column headers, and the format codes used as description text. - Use the
Range.NumberValueproperty to write the values, and set the corresponding format codes with theRange.NumberFormatproperty. - Use the
Workbook.SaveToFile()method to save the workbook, then release resources withWorkbook.Dispose().
Here is a complete code example showing how to set number formats with different decimal places and thousands separators for cells in React:
function App() {
const setDecimalPlacesAndThousands = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS for text measurement
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Write the title and column headers
sheet.Range.get("B1").Text = "Number Formatting Sample";
sheet.Range.get("B3").Text = "Format Code";
sheet.Range.get("C3").Text = "Result";
// Write the format code in column B, write the value in column C and apply the corresponding number format
sheet.Range.get("B4").Text = "0";
sheet.Range.get("C4").NumberValue = 1234.5678;
sheet.Range.get("C4").NumberFormat = "0";
sheet.Range.get("B5").Text = "0.00";
sheet.Range.get("C5").NumberValue = 1234.5678;
sheet.Range.get("C5").NumberFormat = "0.00";
sheet.Range.get("B6").Text = "#,##0.00";
sheet.Range.get("C6").NumberValue = 1234.5678;
sheet.Range.get("C6").NumberFormat = "#,##0.00";
// Add a background color to the format-code cells and set the column widths
sheet.Range.get("B4:B6").Style.KnownColor = xlsModule.ExcelColors.Gray25Percent;
sheet.SetColumnWidth(2, 26);
sheet.SetColumnWidth(3, 20);
// Save the document
const outputFileName = 'NumberFormat_Decimals_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Set Decimal Places and Thousands Separator</h1>
<button onClick={setDecimalPlacesAndThousands}>
Start
</button>
</div>
);
}
export default App;
The worksheet after setting decimal places and thousands separator:

Set Currency Format and Highlight Negative Values
In financial reports, amounts are usually displayed in currency format, while negative numbers need to be highlighted so they can be spotted quickly. An Excel number format code can consist of several parts separated by semicolons, so positive and negative values in the same column can be displayed differently, and negative values can be colored on their own.
The steps are:
- Load the font file into the VFS for text measurement.
- Create a
Workbookobject and get the first worksheet withWorkbook.Worksheets.get(0). - Use the
Range.Textproperty to write the title, column headers, and the currency format codes used as description text. - Use the
Range.NumberValueproperty to write the values (including negative numbers), and set the format codes that contain a negative part with theRange.NumberFormatproperty. - Use the
Workbook.SaveToFile()method to save the workbook, then release resources withWorkbook.Dispose().
Here is a complete code example showing how to set a currency format for amounts in React and display negative numbers in red:
function App() {
const setCurrencyFormat = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS for text measurement
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Write the title and column headers
sheet.Range.get("B1").Text = "Number Formatting Sample";
sheet.Range.get("B3").Text = "Format Code";
sheet.Range.get("C3").Text = "Result";
// Set the currency format: two decimal places with a thousands separator
sheet.Range.get("B4").Text = "$#,##0.00";
sheet.Range.get("C4").NumberValue = 1234.5678;
sheet.Range.get("C4").NumberFormat = "$#,##0.00";
// Negative numbers with a thousands separator displayed in red
sheet.Range.get("B5").Text = "#,##0.00;[Red]-#,##0.00";
sheet.Range.get("C5").NumberValue = -1234.5678;
sheet.Range.get("C5").NumberFormat = "#,##0.00;[Red]-#,##0.00";
// Negative numbers with two decimal places displayed in red
sheet.Range.get("B6").Text = "0.00;[Red]-0.00";
sheet.Range.get("C6").NumberValue = -1234.5678;
sheet.Range.get("C6").NumberFormat = "0.00;[Red]-0.00";
// Add a background color to the format-code cells and set the column widths
sheet.Range.get("B4:B6").Style.KnownColor = xlsModule.ExcelColors.Gray25Percent;
sheet.SetColumnWidth(2, 26);
sheet.SetColumnWidth(3, 20);
// Save the document
const outputFileName = 'NumberFormat_Currency_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Set Currency Format and Highlight Negative Values</h1>
<button onClick={setCurrencyFormat}>
Start
</button>
</div>
);
}
export default App;
The worksheet after setting the currency format and highlighting negative values:

Set Percentage, Scientific Notation and Other Formats
Besides the common decimal, thousands separator and currency formats, reports often call for percentages, scientific notation and Chinese uppercase amounts. Percentages make proportions easier to compare, scientific notation suits very large or very small numbers, and Chinese uppercase is used on formal financial documents.
The steps are:
- Load the font file into the VFS for text measurement.
- Create a
Workbookobject and get the first worksheet withWorkbook.Worksheets.get(0). - Use the
Range.Textproperty to write the title, column headers, and the format codes used as description text. - Use the
Range.NumberValueproperty to write the values, and set the percentage, scientific notation or Chinese uppercase format codes respectively with theRange.NumberFormatproperty. - Use the
Workbook.SaveToFile()method to save the workbook, then release resources withWorkbook.Dispose().
Here is a complete code example showing how to set percentage, scientific notation and Chinese uppercase formats for cells in React:
function App() {
const setSpecialNumberFormat = async () => {
// Get the Spire.XLS WASM module
const xlsModule = window.wasmModule?.spirexls;
// Check whether the module is ready
if (!xlsModule) {
alert('Spire.Xls is not ready yet');
return;
}
// Load the font into the VFS for text measurement
await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
// Create a new workbook and get the first worksheet
const workbook = new xlsModule.Workbook();
const sheet = workbook.Worksheets.get(0);
// Write the title and column headers
sheet.Range.get("B1").Text = "Number Formatting Sample";
sheet.Range.get("B3").Text = "Format Code";
sheet.Range.get("C3").Text = "Result";
// Percentage format: the stored value is multiplied by 100 and a percent sign is shown
sheet.Range.get("B4").Text = "0.00%";
sheet.Range.get("C4").NumberValue = 0.1234;
sheet.Range.get("C4").NumberFormat = "0.00%";
// Scientific notation format
sheet.Range.get("B5").Text = "0.00E+00";
sheet.Range.get("C5").NumberValue = 123456789;
sheet.Range.get("C5").NumberFormat = "0.00E+00";
// Chinese uppercase format (uppercase for RMB amounts)
sheet.Range.get("B6").Text = "[DBNum2][$-804]General";
sheet.Range.get("C6").NumberValue = 1234567;
sheet.Range.get("C6").NumberFormat = "[DBNum2][$-804]General";
// Add a background color to the format-code cells and set the column widths
sheet.Range.get("B4:B6").Style.KnownColor = xlsModule.ExcelColors.Gray25Percent;
sheet.SetColumnWidth(2, 26);
sheet.SetColumnWidth(3, 20);
// Save the document
const outputFileName = 'NumberFormat_Special_output.xlsx';
workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
// Release resources
workbook.Dispose();
// Read the converted file from the VFS and trigger a download
const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
const blob = new Blob([fileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = outputFileName;
a.click();
URL.revokeObjectURL(url);
};
return (
<div style={{ textAlign: 'center', height: '300px' }}>
<h1>Set Percent, Scientific Notation and Other Formats</h1>
<button onClick={setSpecialNumberFormat}>
Start
</button>
</div>
);
}
export default App;
The worksheet after setting percentage, scientific notation and other special formats:

FAQ
The displayed value does not change after setting the number format
Cause: The value written to the cell is actually stored as text, or the data itself is not numeric, so NumberFormat cannot take effect on a number.
Solution: Make sure the value is written with the Range.NumberValue property (rather than a Text or Value string) before setting the NumberFormat, for example:
sheet.Range.get("C4").NumberValue = 1234.5678;
sheet.Range.get("C4").NumberFormat = "0.00";
The value is enlarged after using the percentage format
Cause: Excel displays a percentage format as "stored value × 100". For example, the stored value 12.34 combined with the 0.00% format is displayed as 1234.00%, not 12.34%.
Solution: To display 12.34%, the stored value should be 0.1234. If the original data was entered as a percentage number, divide it by 100 before setting the format.
Negative numbers are not displayed in red
Cause: When a format code contains only one section, positive numbers, negative numbers and zeros all use that section, so [Red] in it affects every value. The color applies only to negative numbers when it is placed in the negative section.
Solution: Split the positive and negative parts with a semicolon and put [Red] in the negative part, for example 0.00;[Red]-0.00.
Obtain a Free License
Spire.XLS for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.