Co-edit Documents with Spire.OfficeJS

2026-11-04 08:57:31 Written by Nina Tang

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.

How co-editing works

  1. User 1 and User 2 open the document with the same co-editing identifier (that is, the same fileInfo.primary).
  2. User 1 edits the document.
  3. The editor reports the changes to the co-authoring service (the service that coAuthorUrl points to).
  4. The co-authoring service distributes the changes to User 2's editor.
  5. 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:

How the editor works underneath


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:

  1. The same primary: fileInfo.primary is not an ordinary "file ID" but the identity of the current co-editing version. Make sure fileInfo.primary is the same (for how it works and how it is generated, see The Co-editing Identifier: fileInfo.primary).
  2. Connect to an Office Server: the editor needs to connect to an Office Server (either locally started or remotely deployed) and use coAuthorUrl to 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.

Fast mode: typing is synchronized in real time

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.

Strict mode: merge after saving

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. true means fast mode, false means strict mode. Fast mode is the default.
  • CollaborationModeOnlyFast: when set to true, 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:

  1. Whether fileAttrs.fileInfo.primary is the same. Different primary values lead to two independent sessions; even if sourceUrl is exactly the same, they will not sync.
  2. Whether an Office Server is configured and connected. editorAttrs.serverless.coAuthorUrl must point to an Office Server reachable by the browser: either started locally (for example http://127.0.0.1:8000) or deployed remotely. If it is missing or misconfigured, co-editing fails (see The Co-authoring Service Address: coAuthorUrl).
  3. sourceUrl only takes effect on the first open or a cache miss. Once the same primary hits the cache, it is no longer read. To switch files, update sourceUrl and use a new primary at 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.

Spire.OfficeJS destroy editor process

  1. The user opens the editor. OpenApi creates the editor on the business page, and the original placeholder <div> is replaced.
  2. Call destroyEditor() to remove the editor. It unbinds the message listener and the mouseup listener on the business page, then replaces the editor iframe with the original placeholder <div>.
  3. 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:

Effect of destroying the editor

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:

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:

  1. Load the font file into the VFS for text measurement.
  2. Create a Workbook object and get the first worksheet with Workbook.Worksheets.get(0).
  3. Use the Range.Text property to write the title, column headers, and the format codes used as description text.
  4. Use the Range.NumberValue property to write the values, and set the corresponding format codes with the Range.NumberFormat property.
  5. Use the Workbook.SaveToFile() method to save the workbook, then release resources with Workbook.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 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:

  1. Load the font file into the VFS for text measurement.
  2. Create a Workbook object and get the first worksheet with Workbook.Worksheets.get(0).
  3. Use the Range.Text property to write the title, column headers, and the currency format codes used as description text.
  4. Use the Range.NumberValue property to write the values (including negative numbers), and set the format codes that contain a negative part with the Range.NumberFormat property.
  5. Use the Workbook.SaveToFile() method to save the workbook, then release resources with Workbook.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 Currency Format and Highlight 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:

  1. Load the font file into the VFS for text measurement.
  2. Create a Workbook object and get the first worksheet with Workbook.Worksheets.get(0).
  3. Use the Range.Text property to write the title, column headers, and the format codes used as description text.
  4. Use the Range.NumberValue property to write the values, and set the percentage, scientific notation or Chinese uppercase format codes respectively with the Range.NumberFormat property.
  5. Use the Workbook.SaveToFile() method to save the workbook, then release resources with Workbook.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:

Set Percentage, Scientific Notation and Other 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.

Page 1 of 371
page 1