Shapes are graphic elements in Excel that enhance the visual appeal of a worksheet and convey information intuitively, such as arrows, rectangles, ovals, and stars. With shapes, you can add annotations, process-flow indicators, or decorative elements next to your data, making reports more vivid and easier to read. 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 required. It provides a complete API for adding shapes and customizing their appearance (such as fill, rotation angle, text, and shadow), reading text and images from shapes, and deleting specified or all shapes.

This article covers three core features:

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.


Add Shapes to Excel

Adding shapes to Excel can highlight key data and beautify the layout of a worksheet. With Spire.XLS for JavaScript, you can add a shape and set its position (row, column) and size (width, height) at once using the PrstGeomShapes.AddPrstGeomShape() method, and then customize its appearance through the shape's properties — set solid, gradient, texture, or picture fill via Fill, add text via Text, set the rotation angle via Rotation, apply a shadow effect via Shadow, and control visibility via Visible. The steps are as follows:

  1. Create a Workbook object and get the default worksheet.
  2. Add shapes using PrstGeomShapes.AddPrstGeomShape(), setting the shape type, position, and size through the parameters.
  3. Set solid, gradient, texture, or picture fill for the shapes via the Fill property.
  4. Add text to a shape via the Text property, and set the rotation angle via the Rotation property.
  5. Set a shadow effect for a shape via the Shadow property.
  6. Save the workbook to an Excel file using SaveToFile().

Below is a complete code example demonstrating how to add and customize various shapes in React:

function App() {
  const addShapes = 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 picture into the virtual file system (VFS)
    await window.spire.FetchFileToVFS('SpireXls.png', '', `${process.env.PUBLIC_URL}/image/`);

    // Create a new workbook and get the default worksheet
    const workbook = new xlsModule.Workbook();
    let sheet = workbook.Worksheets.get(0);

    // Add a triangle shape and fill it with a solid color
    let triangle = sheet.PrstGeomShapes.AddPrstGeomShape(2, 2, 100, 100, xlsModule.PrstGeomShapeType.Triangle);
    triangle.Fill.ForeColor = xlsModule.Color.get_Yellow();
    triangle.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
    // Add text to the triangle and set its rotation angle
    triangle.Text = 'Triangle';
    triangle.Rotation = 45;

    // Add a heart shape and fill it with a gradient color
    let heart = sheet.PrstGeomShapes.AddPrstGeomShape(2, 5, 100, 100, xlsModule.PrstGeomShapeType.Heart);
    heart.Fill.ForeColor = xlsModule.Color.get_Red();
    heart.Fill.FillType = xlsModule.ShapeFillType.Gradient;
    // Set the shadow style for the heart
    heart.Shadow.Angle = 90;
    heart.Shadow.Distance = 10;
    heart.Shadow.Size = 150;
    heart.Shadow.Color = xlsModule.Color.get_Gray();
    heart.Shadow.Blur = 30;
    heart.Shadow.Transparency = 1;
    heart.Shadow.HasCustomStyle = true;

    // Add an arrow shape
    let arrow = sheet.PrstGeomShapes.AddPrstGeomShape(10, 2, 100, 100, xlsModule.PrstGeomShapeType.CurvedRightArrow);

    // Add a cloud shape and fill it with a picture
    let cloud = sheet.PrstGeomShapes.AddPrstGeomShape(10, 5, 100, 100, xlsModule.PrstGeomShapeType.Cloud);
    cloud.Fill.CustomPicture({ im: new xlsModule.Stream('SpireXls.png'), name: 'SpireXls.png' });

    // Save the workbook
    const outputFileName = 'AddShapes.xlsx';
    workbook.SaveToFile(outputFileName);
    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>Add Shapes</h1>
      <button onClick={addShapes}>
        Generate
      </button>
    </div>
  );
}

export default App;

Shapes added to Excel with Spire.XLS for JavaScript

Shapes added to Excel with Spire.XLS for JavaScript


Read Text and Images from Excel Shapes

Reading the text and images from shapes helps you extract the data inside shapes in batch, or reuse and archive shape resources. With Spire.XLS for JavaScript, you can load an Excel file containing shapes, get a specified shape by index via PrstGeomShapes.get(), then read its text content via the Text property and get its fill picture via Fill.Picture. The steps are as follows:

  1. Create a Workbook object and load an existing Excel file containing shapes.
  2. Get the worksheet via workbook.Worksheets.get().
  3. Get a specified shape by index using sheet.PrstGeomShapes.get().
  4. Read the text in the shape via the Text property.
  5. Read the fill picture in the shape via the Fill.Picture property.
  6. Save the read text and image as txt and png files.

Below is a complete code example demonstrating how to read text and images from shapes in React (the example loads the AddShapes.xlsx file generated in the previous section):

function App() {
  const readShapes = 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 sample file containing shapes into the virtual file system (VFS)
    let excelFileName = 'AddShapes.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the existing file
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: excelFileName });

    // Get the first worksheet
    let sheet = workbook.Worksheets.get(0);

    // Get the first shape (triangle) and read the text inside it
    let triangle = sheet.PrstGeomShapes.get(0);
    let text = triangle.Text;

    // Get the fourth shape (cloud) and read the picture inside it
    let cloud = sheet.PrstGeomShapes.get(3);
    let image = cloud.Fill.Picture;
    const imageFileName = 'ExtractImageFromShape.png';
    image.Save(imageFileName);

    workbook.Dispose();

    // Save the read text to a txt file and trigger download
    const textFileName = 'ExtractTextFromShape.txt';
    const textBlob = new Blob([`The text in the first shape is: ${text}`], { type: 'text/plain;charset=utf-8' });
    const textUrl = URL.createObjectURL(textBlob);
    const a1 = document.createElement('a');
    a1.href = textUrl;
    a1.download = textFileName;
    a1.click();
    URL.revokeObjectURL(textUrl);

    // Read the image file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(imageFileName);
    const blob = new Blob([fileArray], { type: 'application/png' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = imageFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Read Text and Image from Shapes</h1>
      <button onClick={readShapes}>
        Generate
      </button>
    </div>
  );
}

export default App;

Text and images read from Excel shapes with Spire.XLS for JavaScript

Text and images read from Excel shapes with Spire.XLS for JavaScript


Delete Shapes in Excel

When shapes are no longer needed, deleting them in time keeps the worksheet clean and reduces the file size. With Spire.XLS for JavaScript, you can delete a specified shape via the Remove() method, or iterate through the shape collection and call Remove() on each shape to clear all shapes in a worksheet. The steps are as follows:

  1. Create a Workbook object and load an existing Excel file containing shapes.
  2. Get the worksheet via workbook.Worksheets.get().
  3. Get a specified shape using sheet.PrstGeomShapes.get(), and call its Remove() method to delete the shape.
  4. Save the workbook to an Excel file using SaveToFile().

Below is a complete code example demonstrating how to delete shapes in React (the example loads the AddShapes.xlsx file generated in the previous section):

function App() {
  const deleteShapes = 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 sample file containing shapes into the virtual file system (VFS)
    let excelFileName = 'AddShapes.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the existing file
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: excelFileName });

    // Get the first worksheet
    let sheet = workbook.Worksheets.get(0);

    // Delete the first shape in the worksheet
    sheet.PrstGeomShapes.get(0).Remove();

    // Delete all the shapes in the worksheet
    // for (let i = sheet.PrstGeomShapes.Count - 1; i >= 0; i--) {
    //   sheet.PrstGeomShapes.get(i).Remove();
    // }

    // Save the workbook
    const outputFileName = 'DeleteShapes.xlsx';
    workbook.SaveToFile(outputFileName);
    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>Delete Shapes</h1>
      <button onClick={deleteShapes}>
        Generate
      </button>
    </div>
  );
}

export default App;

Specified shape deleted from Excel with Spire.XLS for JavaScript

Specified shape deleted from Excel with Spire.XLS for JavaScript


FAQ

How to get the name and type of a shape?

Cause: When a worksheet contains many shapes, you may need to identify and locate shapes by their name or type rather than by index.

Solution: Read the Name and PrstShapeType properties of the shape to get its name and type:

// Get the worksheet
let sheet = workbook.Worksheets.get(0);
// Get the first shape
let shape = sheet.PrstGeomShapes.get(0);
// Get the name of the shape
let shapeName = shape.Name;
// Get the type of the shape
let shapeType = shape.PrstShapeType;

How to check whether a shape is currently visible?

Cause: After loading shapes from a file, you may need to determine whether a shape is hidden so that you can decide whether to process it further.

Solution: Read the Visible property of the shape to know its visibility state:

// Get the worksheet
let sheet = workbook.Worksheets.get(0);
// Get the first shape
let shape = sheet.PrstGeomShapes.get(0);
// Check whether the shape is visible
let isVisible = shape.Visible;

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.

When browsing an Excel worksheet that contains a large amount of data, pinning the header or key columns can significantly improve the efficiency of data viewing. The freeze panes feature keeps the specified rows or columns visible while scrolling. Querying the frozen pane range confirms which areas of the current worksheet are frozen. Unfreezing panes restores the normal browsing mode when the fixed display is no longer needed. Spire.XLS for JavaScript completes these operations directly in the browser based on WebAssembly, and manages input and output files through the virtual file system (VFS), without requiring backend service support.

This article introduces three core feature points:

For installation and project configuration, refer to Integrate Spire.XLS for JavaScript in a React Project. The following examples assume that Spire.XLS is installed and the WebAssembly module has been initialized.


Freeze Panes

When a worksheet contains a large amount of data, freezing panes can pin the header or a specific area so that you can always see the key rows or columns while scrolling through the data. Spire.XLS for JavaScript freezes the panes above and to the left of the specified position through the FreezePanes method. For example, FreezePanes(2, 1) freezes the first row, keeping it visible when scrolling vertically.

function App() {
  const sheetToSVG = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check whether the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font and the Excel file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'FreezePanes.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    // Load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Freeze the first row
    sheet.FreezePanes(2, 1);

    // Set the width of the second column
    sheet.SetColumnWidth(2, 10);

    const outputFileName = "FreezePanes_output.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Dispose of the workbook object to release resources
    workbook.Dispose();

    // Read the converted 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>Freeze Panes</h1>
      <button onClick={sheetToSVG}>
        Start
      </button>
    </div>
  );
}

export default App;

Original document Original document After freezing the first row After freezing the first row


Get the Freeze Pane Range

When working with frozen panes, sometimes you need to confirm the position of the frozen panes in the current worksheet. Spire.XLS for JavaScript obtains the row index and column index of the frozen panes through the GetFreezePanes method, and a return value of 0 indicates that the corresponding direction is not frozen.

function App() {
  const sheetToSVG = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check whether the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font and the Excel file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'GetFreezePaneRange.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    // Load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Get the row index and column index of the frozen panes
    const indexs = sheet.GetFreezePanes();
    const rowIndex = indexs[0];
    const colIndex = indexs[1];

    // Write the query result to a text file
    const outputFileName = "GetFreezePaneRange_output.txt";
    window.dotnetRuntime.Module.FS.writeFile(outputFileName, `Row index: ${rowIndex}, column index: ${colIndex}`);

    // Dispose of the workbook object to release resources
    workbook.Dispose();

    // Read the converted file from the VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Get Freeze Pane Range</h1>
      <button onClick={sheetToSVG}>
        Start
      </button>
    </div>
  );
}

export default App;

Original document with frozen panes Original document with frozen panes Query result Query result


Unfreeze Panes

When the fixed display is no longer needed, you can cancel the frozen panes that have been set in the worksheet through the RemovePanes method and restore normal scrolling.

function App() {
  const sheetToSVG = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check whether the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the font and the Excel file into the VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Template_Xls_2.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    // Load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Unfreeze the panes
    sheet.RemovePanes();

    const outputFileName = "UnfreezeExcelPanes_output.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Dispose of the workbook object to release resources
    workbook.Dispose();

    // Read the converted 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>Unfreeze Panes</h1>
      <button onClick={sheetToSVG}>
        Start
      </button>
    </div>
  );
}

export default App;

Before unfreezing Before unfreezing After unfreezing After unfreezing

FAQ

The first row still scrolls after freezing panes

Reason: The parameters of the FreezePanes method are set incorrectly, so the frozen area is not the expected row or column.

Solution: The FreezePanes method uses the specified position as the boundary and freezes the panes above and to the left of that position. For example, use FreezePanes(2, 1) to freeze the first row, FreezePanes(3, 1) to freeze the first two rows, and FreezePanes(2, 2) to freeze both the first row and the first column.

Querying the freeze pane range returns 0

Reason: The worksheet has not set any frozen panes, so the queried row and column indexes are 0.

Solution: Call the FreezePanes method to set frozen panes first, and then call GetFreezePanes to query the frozen range.

The freeze effect still shows after unfreezing panes

Reason: The workbook was not saved correctly after unfreezing, or the file opened is the one before the modification.

Solution: After calling the RemovePanes method, be sure to save the workbook with SaveToFile and open the output file to confirm the unfreeze effect.


Get a Free License

If you want to remove the evaluation message in the result documents or get rid of the feature limitations, please contact sales to obtain a 30-day temporary license.

Images are one of the most intuitive forms of content presentation and distribution, while PDF documents preserve the original layout and are widely used for the storage and transmission of formal files. When displaying PDF content on web pages, mini programs, social platforms, or emails, distributing PDF files directly is often inconvenient — converting them to image formats such as PNG or JPEG first enables quick preview and sharing. Conversely, consolidating scanned documents or image assets into PDF makes batch archiving and cross-platform distribution easier. Real-world business often requires flexible switching between the two forms: converting PDF contracts to images for online preview and quick sharing, or converting scanned image assets to PDF for unified archiving and circulation.

Spire.PDF for JavaScript performs bidirectional conversion between PDF and images entirely in the browser via WebAssembly, managing input and output files through a virtual file system (VFS) with no backend server required.

This article covers two core features:

For installation and project setup, refer to Integrating Spire.PDF for JavaScript in a React Project. The examples below assume Spire.PDF is installed and the WebAssembly module is initialized.


Convert PDF to Image

The core of PDF-to-image conversion is to render the content, fonts, and graphics elements of every page in a PDF document into independent bitmap data. Spire.PDF for JavaScript generates an image stream for each page through the PdfDocument object's SaveAsImage method, loops through all Pages.Count pages and saves each page as a PNG image with stream.Save, then bundles the images into a ZIP file with JSZip for a one-click download, without needing to handle pixel and page coordinate mapping manually.

import JSZip from "jszip";

function App() {
  const convertToImage = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check if the WASM module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load the PDF file and fonts into VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Flowers.pdf';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create PdfDocument object and load the PDF document
    let doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // Create an output directory to hold the converted images
    let outputDirectoryName = "ImagesFolders/";
    window.dotnetRuntime.Module.FS.mkdirTree(outputDirectoryName);

    // Loop through each page and save it as an image
    for (let i = 0; i < doc.Pages.Count; i++) {
      const outputFileName = outputDirectoryName + "ConvertedImages_" + i + ".png";
      let stream = doc.SaveAsImage({ pageIndex: i });
      stream.Save(outputFileName);
      stream.Dispose();
    }

    doc.Dispose();

    // Read the converted files from VFS and trigger download
    const zip = new JSZip();
    let items = await window.dotnetRuntime.Module.FS.readdir(outputDirectoryName);
    items = items.filter((item) => item !== "."

      && item !== "..");
    for (const item of items) {
      const itemPath = `${outputDirectoryName}/${item}`;
      const fileData = await window.dotnetRuntime.Module.FS.readFile(itemPath);
      zip.file(item, fileData);
    }

    // Convert the ZIP to a Blob and trigger the browser download
    const zipBlob = await zip.generateAsync({ type: "blob" });
    const url = URL.createObjectURL(zipBlob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'ImagesFolders';
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Convert PDF To Image</h1>
      <button onClick={convertToImage}>
        Generate
      </button>
    </div>
  );
}

export default App;

Each page of the PDF exported as a PNG image via SaveAsImage and bundled into a ZIP file for download

Each page of the PDF exported as a PNG image via SaveAsImage and bundled into a ZIP file for download

Adjust the DPI Resolution of Exported Images

When exporting images with the SaveAsImage method, the default resolution is 96 DPI, which is suitable for screen preview, but text and lines may appear jagged or blurry when zoomed in. For sharper images, specify the resolution via the dpiX and dpiY parameters of SaveAsImage, for example set it to 150 DPI:

// Export each page as an image at 150 DPI
for (let i = 0; i < doc.Pages.Count; i++) {
  let stream = doc.SaveAsImage({ pageIndex: i, dpiX: 150, dpiY: 150 });
  stream.Save(outputDirectoryName + "highres_" + i + ".png");
  stream.Dispose();
}

The higher the DPI value, the sharper the exported image, but the larger the file size. Choose a balance between clarity and file size based on your actual use case.


Convert Image to PDF

Image-to-PDF conversion is commonly used to consolidate scanned documents or design assets into PDF for archiving. Spire.PDF for JavaScript creates a new document with the PdfDocument object, loads the image with the PdfImage.FromFile method, adds a page via Pages.Add, draws the image onto the page at its original size with the Canvas.DrawImage method, and finally saves it as a standard PDF with the SaveToFile method using the FileFormat.PDF enum value.

function App() {
  const convertImageToPDF = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check if the WASM module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load the image file into VFS
    const inputFileName = 'Scenery.png';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create a PdfDocument object
    let doc = new pdfModule.PdfDocument();

    // Add a page
    let page = doc.Pages.Add();

    // Load the image
    let image = pdfModule.PdfImage.FromFile(inputFileName);

    // Calculate the scale ratio so the image fits the page completely
    let widthFitRate = image.PhysicalDimension.Width / page.Canvas.ClientSize.Width;
    let heightFitRate = image.PhysicalDimension.Height / page.Canvas.ClientSize.Height;
    let fitRate = Math.max(widthFitRate, heightFitRate);

    // Calculate the scaled dimensions of the image
    let fitWidth = image.PhysicalDimension.Width / fitRate;
    let fitHeight = image.PhysicalDimension.Height / fitRate;

    // Draw the image onto the page
    page.Canvas.DrawImage({ image: image, x: 0, y: 30, width: fitWidth, height: fitHeight });

    const outputFileName = 'ImageToPDF.pdf';

    // Save as PDF format
    doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.PDF });
    doc.Close();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/pdf' });
    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>Convert Image To PDF</h1>
      <button onClick={convertImageToPDF}>
        Generate
      </button>
    </div>
  );
}

export default App;

PDF document generated after loading an image via PdfImage.FromFile and drawing it with Canvas.DrawImage

PDF document generated after loading an image via PdfImage.FromFile and drawing it with Canvas.DrawImage

Load Images from a Memory Stream

Besides loading directly from a file with PdfImage.FromFile, images can also be loaded from a memory stream via the PdfImage.FromStream method. This approach suits scenarios where the image data comes from an API response or a database field, or where bytes need to be read before processing. See the code below:

// Read image bytes from VFS and build a memory stream
let bytes = window.dotnetRuntime.Module.FS.readFile(inputFileName);
let stream = new pdfModule.Stream(bytes);

// Load the image from the memory stream
let image = pdfModule.PdfImage.FromStream(stream);

The image can then be drawn onto a PDF page with the page.Canvas.DrawImage method and saved as a standard PDF using SaveToFile.


FAQ

Garbled text in the converted image

Reason: PDF relies on font embedding to ensure consistent cross-platform rendering. If the input PDF uses non-embedded fonts and the corresponding font files are not loaded in the VFS, text may appear garbled after conversion.

Solution: Make sure the required TrueType font files (e.g., ARIALUNI.TTF) are loaded into the /Library/Fonts/ directory in VFS before calling the conversion. ARIALUNI.TTF covers common CJK characters and is the recommended font for ensuring conversion quality.

Which image formats are supported for conversion?

Reason: Different business scenarios require different bitmap formats. For example, PNG is commonly used for web preview and JPEG for photos.

Solution: Spire.PDF for JavaScript can render PDF pages to common bitmap formats such as PNG, JPEG, and BMP. After generating the image stream with SaveAsImage, simply replace the file extension of the output file name with the target format (e.g., .jpg, .bmp, .png) in stream.Save to output the corresponding image format.


Get a Free License

If you want to remove the evaluation messages in the resulting documents or get rid of functional limitations, contact sales to obtain a 30-day temporary license.

XPS (XML Paper Specification) is a fixed-layout document format introduced by Microsoft, widely used in electronic document printing, archiving, and distribution scenarios, with native support in the Windows platform ecosystem. XPS describes document structure based on XML, offering advantages such as clear structure, easy validation, and digital signing. Meanwhile, PDF remains indispensable as an internationally recognized document format for cross-platform distribution. Real-world business often requires flexible switching between the two formats: converting existing PDF contracts to XPS for printing and archiving in Windows environments, or converting XPS documents to PDF for cross-platform distribution and collaboration.

Spire.PDF for JavaScript performs bidirectional conversion between PDF and XPS entirely in the browser via WebAssembly, managing input and output files through a virtual file system (VFS) with no backend server required.

This article covers two core features:

For installation and project setup, refer to Integrating Spire.PDF for JavaScript in a React Project. The examples below assume Spire.PDF is installed and the WebAssembly module is initialized.


Convert PDF to XPS

The core of PDF-to-XPS conversion is to re-encode the page content, fonts, and graphics elements from a PDF document into an XML description structure compliant with the XPS standard. Spire.PDF for JavaScript accomplishes this in one step through the PdfDocument object's SaveToFile method with the FileFormat.XPS enum value, eliminating the need to handle underlying format differences manually.

function App() {
  const convertToXPS = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check if the WASM module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load fonts and PDF file into VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Reading_EN.pdf';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create PdfDocument object and load the PDF document
    let doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // Define the output file name for XPS format
    const outputFileName = 'OutputXPS.xps';

    // Save as XPS format
    doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.XPS });
    doc.Close();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/vnd.ms-xpsdocument' });
    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>Convert PDF To XPS</h1>
      <button onClick={convertToXPS}>
        Generate
      </button>
    </div>
  );
}

export default App;

XPS output generated after conversion via SaveToFile with FileFormat.XPS

XPS output generated after conversion via SaveToFile with FileFormat.XPS


Convert XPS to PDF

XPS-to-PDF conversion is a common requirement in document cross-platform distribution scenarios. Spire.PDF for JavaScript loads XPS fixed-layout documents through the PdfDocument object's LoadFromXPS method and then exports them as standard PDF files via the SaveToFile method with the FileFormat.PDF enum value, preserving the original document's layout and visual appearance.

function App() {
  const convertXPSToPDF = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check if the WASM module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load the XPS file into VFS
    const inputFileName = 'Lease_Agreement_EN.xps';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create PdfDocument object and load the XPS document
    let doc = new pdfModule.PdfDocument();
    doc.LoadFromXPS(inputFileName);

    // Define the output file name for PDF format
    const outputFileName = 'OutputPDF.pdf';

    // Save as PDF format
    doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.PDF });
    doc.Close();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/pdf' });
    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>Convert XPS To PDF</h1>
      <button onClick={convertXPSToPDF}>
        Generate
      </button>
    </div>
  );
}

export default App;

PDF document generated after loading XPS via the PdfDocument LoadFromXPS method and converting

PDF document generated after loading XPS via the PdfDocument LoadFromXPS method and converting


FAQ

Can encrypted PDFs be converted to XPS?

Password-protected encrypted PDFs cannot be saved as XPS directly via SaveToFile — the document must be decrypted first.

Solution: Provide the password when loading the PDF via the second parameter of LoadFromFile, then save as XPS:

// Load a password-protected PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName, "password");

// Save as XPS format
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.XPS });
doc.Close();

Get a Free License

If you want to remove the evaluation messages in the resulting documents or get rid of functional limitations, contact sales to obtain a 30-day temporary license.

Page breaks are an important tool for controlling the print layout of Excel. They determine where data is divided across printed pages. Setting page breaks properly prevents data from being broken apart pointlessly when printing, resulting in clean, readable paper or PDF reports. Spire.XLS for JavaScript uses WebAssembly to add, preview, and remove page breaks directly in the browser, managing input and output files through a virtual file system (VFS) — no backend server required.

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.


Add Page Breaks

When printing reports, we often want to split data by a fixed number of rows and columns, for example printing a fixed number of data rows per page. Spire.XLS for JavaScript adds horizontal page breaks using the HPageBreaks.Add method and vertical page breaks using the VPageBreaks.Add method, enabling precise page break control.

function App() {
  const sheetToSVG = 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 fonts and the Excel file into VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Template_Xls_4.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    // Load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Add a horizontal page break at row E4
    sheet.HPageBreaks.Add(sheet.Range.get("E4"));
    // Add a vertical page break at column C4
    sheet.VPageBreaks.Add(sheet.Range.get("C4"));

    const outputFileName = "AddPageBreakInXlsFile.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Release the workbook object to free resources
    workbook.Dispose();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Add Page Break</h1>
      <button onClick={sheetToSVG}>
        Start
      </button>
    </div>
  );
}

export default App;

Original document Original document Add page break Add page break


Page Break View Zoom Scale Setting

When viewing page break positions in the view mode, Spire.XLS for JavaScript supports setting the zoom scale of the page break preview view through the ZoomScalePageBreakView property.

function App() {
  const sheetToSVG = 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 fonts and the Excel file into VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Template_Xls_4.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    // Load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Set the zoom scale of the page break preview view
    sheet.ZoomScalePageBreakView = 80;

    const outputFileName = "PageBreakPreview.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Release the workbook object to free resources
    workbook.Dispose();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Page Break Preview</h1>
      <button onClick={sheetToSVG}>
        Start
      </button>
    </div>
  );
}

export default App;

Before setting the zoom scale Before setting the zoom scale After setting the zoom scale After setting the zoom scale


Remove Page Breaks

When page breaks are no longer needed, you can clear all page breaks in a specific direction using the Clear method, or delete the page break at a specific position by index using the RemoveAt method. After removal, you can also switch the worksheet to the page break preview view via the ViewMode property to visually confirm the page break effect.

function App() {
  const sheetToSVG = 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 fonts and the Excel file into VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'PageBreak.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

    // Load the workbook
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: inputFileName });

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Clear all vertical page breaks
    sheet.VPageBreaks.Clear();

    // Remove the first horizontal page break
    sheet.HPageBreaks.RemoveAt(0);

    // Set the view mode to page break preview to check the page break effect
    sheet.ViewMode = xlsModule.ViewMode.Preview;

    const outputFileName = "RemovePageBreak_output.xlsx";
    workbook.SaveToFile({ fileName: outputFileName });

    // Release the workbook object to free resources
    workbook.Dispose();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Remove Page Break</h1>
      <button onClick={sheetToSVG}>
        Start
      </button>
    </div>
  );
}

export default App;

Before removing the page break Before removing the page break After removing the page break After removing the page break

FAQ

Page breaks do not take effect when printing after being added

Cause: The page break was added to a blank area, or the worksheet has a fixed print zoom scale set, causing the actual page break positions during printing to differ from what was expected.

Solution: Confirm that the page break is added on the row or column of a cell containing data, and check the worksheet's print zoom settings. If necessary, adjust the zoom scale through properties such as ZoomScalePageBreakView so the page breaks take effect as expected.

Page break lines still display after removal

Cause: The worksheet is still in page break preview view mode, or there are automatic page breaks that are generated automatically based on the amount of data.

Solution: Automatic page breaks cannot be removed directly by programming; automatic page breaks are determined by the number of data rows, columns, and the page size. They can be eliminated by adjusting row heights, column widths, or the print zoom scale.


Get a Free License

If you want to remove the evaluation messages in the resulting documents, or get rid of functional limitations, please contact sales to obtain a temporary license valid for 30 days.

A pivot chart is a graphical representation of the summarized results of a pivot table, making data comparisons and trends immediately visible. It is an essential tool for data analysis and report presentation. 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 required. It provides a complete API for creating pivot charts based on pivot tables, controlling the display of pivot chart field buttons, and customizing the appearance of pivot chart series.

This article covers three core features:

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.


Create a Pivot Chart in Excel

A pivot chart must be created based on a pivot table. With Spire.XLS for JavaScript, you can first create a pivot table in a worksheet, and then use the Charts.Add() method with the pivotChartType and pivotTable parameters to generate a corresponding pivot chart directly from the pivot table. The steps are as follows:

  1. Create a Workbook object and get the default worksheet.
  2. Populate the worksheet with the source data required for the pivot table.
  3. Create a pivot table cache using PivotCaches.Add().
  4. Add a pivot table using PivotTables.Add(), and drag fields to the row area and the data area.
  5. Add a chart using sheet.Charts.Add(), and create a pivot chart based on the pivot table via the pivotChartType and pivotTable parameters.
  6. Set the position and title of the pivot chart.
  7. Save the workbook to an Excel file using SaveToFile().

Below is a complete code example demonstrating how to create a pivot chart based on a pivot table in React:

function App() {
  const createPivotChart = 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 virtual file system (VFS)
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

    // Create a new workbook and get the default worksheet
    const workbook = new xlsModule.Workbook();
    let sheet = workbook.Worksheets.get(0);

    // Populate the source data for the pivot table
    sheet.Range.get('A1').Value = 'Product';
    sheet.Range.get('B1').Value = 'Month';
    sheet.Range.get('C1').Value = 'Sales';

    sheet.Range.get('A2').Value = 'Apple';
    sheet.Range.get('A3').Value = 'Apple';
    sheet.Range.get('A4').Value = 'Banana';
    sheet.Range.get('A5').Value = 'Apple';
    sheet.Range.get('A6').Value = 'Banana';
    sheet.Range.get('A7').Value = 'Banana';

    sheet.Range.get('B2').Value = 'January';
    sheet.Range.get('B3').Value = 'February';
    sheet.Range.get('B4').Value = 'January';
    sheet.Range.get('B5').Value = 'January';
    sheet.Range.get('B6').Value = 'February';
    sheet.Range.get('B7').Value = 'February';

    sheet.Range.get('C2').Value = '10';
    sheet.Range.get('C3').Value = '15';
    sheet.Range.get('C4').Value = '9';
    sheet.Range.get('C5').Value = '7';
    sheet.Range.get('C6').Value = '8';
    sheet.Range.get('C7').Value = '10';

    // Create a pivot table
    let dataRange = sheet.Range.get('A1:C7');
    let cache = workbook.PivotCaches.Add({ range: dataRange });
    let pivotTable = sheet.PivotTables.Add('Pivot Table', sheet.Range.get({ row: 1, column: 5 }), cache);

    // Drag fields to the row area
    let pf = pivotTable.PivotFields.get_Item('Product');
    pf.Axis = xlsModule.AxisTypes.Row;
    let pf2 = pivotTable.PivotFields.get_Item('Month');
    pf2.Axis = xlsModule.AxisTypes.Row;

    // Drag a field to the data area
    pivotTable.DataFields.Add(pivotTable.PivotFields.get_Item('Sales'), 'Sum of Sales', xlsModule.SubtotalTypes.Sum);

    // Set the pivot table style and calculate the data
    pivotTable.BuiltInStyle = xlsModule.PivotBuiltInStyles.PivotStyleMedium12;
    pivotTable.CalculateData();

    // Create a clustered column chart based on the pivot table
    let chart = sheet.Charts.Add({ pivotChartType: xlsModule.ExcelChartType.ColumnClustered, pivotTable: pivotTable });
    // Set the pivot chart position
    chart.TopRow = 9;
    chart.LeftColumn = 1;
    chart.RightColumn = 9;
    chart.BottomRow = 25;
    // Set the pivot chart title
    chart.ChartTitle = "Pivot Chart";

    // Save the workbook
    const outputFileName = 'PivotChart.xlsx';
    workbook.SaveToFile(outputFileName);
    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 Pivot Chart</h1>
      <button onClick={createPivotChart}>
        Generate
      </button>
    </div>
  );
}

export default App;

Pivot chart created in Excel with Spire.XLS for JavaScript

Pivot chart created in Excel with Spire.XLS for JavaScript


Show or Hide Field Buttons of an Excel Pivot Chart

By default, a pivot chart displays field buttons, allowing users to interactively filter and switch field data. When generating reports, you may want to hide some or all of the field buttons to make the chart cleaner. Spire.XLS for JavaScript provides properties such as DisplayEntireFieldButtons, DisplayValueFieldButtons, DisplayAxisFieldButtons, DisplayLegendFieldButtons, and ShowReportFilterFieldButtons to flexibly control the display of each type of field button. The steps are as follows:

  1. Create a Workbook object and load an existing Excel file containing a pivot chart.
  2. Get the worksheet via workbook.Worksheets.get().
  3. Get the pivot chart object using sheet.Charts.get().
  4. Control whether to display all field buttons via DisplayEntireFieldButtons.
  5. Control the display of each type of field button via DisplayValueFieldButtons, DisplayAxisFieldButtons, DisplayLegendFieldButtons, and ShowReportFilterFieldButtons.
  6. Save the workbook to an Excel file using SaveToFile().

Below is a complete code example demonstrating how to show or hide pivot chart field buttons in React (the example loads the PivotChart.xlsx file generated in the previous section):

function App() {
  const showHideFieldButtons = 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 sample file containing a pivot chart into the virtual file system (VFS)
    let excelFileName = 'PivotChart.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the existing file
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: excelFileName });

    // Get the first worksheet
    let sheet = workbook.Worksheets.get(0);

    // Get the pivot chart
    let chart = sheet.Charts.get(0);

    // Control the display of all field buttons
    chart.DisplayEntireFieldButtons = true;

    // Hide the value field buttons
    chart.DisplayValueFieldButtons = false;
    // Hide the axis field buttons
    chart.DisplayAxisFieldButtons = false;
    // Hide the legend field buttons
    //chart.DisplayLegendFieldButtons = false;
    // Show the report filter field buttons
    //chart.ShowReportFilterFieldButtons = true;

    // Save the workbook
    const outputFileName = 'PivotChartFieldButtons.xlsx';
    workbook.SaveToFile(outputFileName);
    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>Show/Hide PivotChart Field Buttons</h1>
      <button onClick={showHideFieldButtons}>
        Generate
      </button>
    </div>
  );
}

export default App;

Pivot chart field buttons shown or hidden with Spire.XLS for JavaScript

Pivot chart field buttons shown or hidden with Spire.XLS for JavaScript


Set the Format of Excel Pivot Chart Series

Formatting the series of a pivot chart can make the chart more visually appealing and clearly organized, conveying data information more effectively. With Spire.XLS for JavaScript, you can load an Excel file containing a pivot chart, get the pivot chart via the Charts.get() method, then set fill types, colors, and border styles via the series' DataFormat property, and set formats such as the gap width of the data bars via the format object returned by the GetCommonSerieFormat() method. The steps are as follows:

  1. Create a Workbook object.
  2. Load an Excel file containing a pivot chart using the LoadFromFile() method.
  3. Get a specific worksheet in the Excel file using the Worksheets.get() method.
  4. Get the pivot chart in the worksheet using the Charts.get() method.
  5. Set the position and title of the pivot chart.
  6. Get the data series of the pivot chart using the Series.get() method.
  7. Set fill types, colors, and border styles via the DataFormat property, and set formats such as the gap width of the data bars via the GetCommonSerieFormat() method.
  8. Save the generated file using the SaveToFile() method.

Below is a complete code example demonstrating how to set the format of pivot chart series in React (the example loads the PivotChart.xlsx file containing a pivot chart generated in the previous section):

function App() {
  const formatPivotChartSeries = 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 sample file containing a pivot table into the virtual file system (VFS)
    let excelFileName = 'PivotChart.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Create a Workbook object
    const workbook = new xlsModule.Workbook();
    // Load the Excel file
    workbook.LoadFromFile({ fileName: excelFileName });

    // Get the first worksheet
    let sheet = workbook.Worksheets.get(0);

    // Get the pivot chart
    let chart = sheet.Charts.get(0);

    // Set the pivot chart position
    chart.TopRow = 1;
    chart.LeftColumn = 8;
    chart.RightColumn = 18;
    chart.BottomRow = 15;

    // Set the chart title
    chart.ChartTitle = "";

    // Add a series to the pivot chart
    let series = chart.Series.get(0);

    // Set the gap width of the data bars
    series.GetCommonSerieFormat().GapWidth = 10;
    // series.GetCommonSerieFormat().Overlap = 100;

    // Set the fill type, foreground color, and background color of the series
    series.DataFormat.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
    series.DataFormat.ForeGroundColor = xlsModule.Color.get_Red();
    series.DataFormat.BackGroundColor = xlsModule.Color.get_White();

    // Set the border color, line style, and line weight of the series
    series.DataFormat.LineProperties.Pattern = xlsModule.ChartLinePatternType.Solid;
    series.DataFormat.LineProperties.Color = xlsModule.Color.get_Blue();
    series.DataFormat.LineProperties.CustomLineWeight = 2.5;

    // Add a shadow effect to the series
    series.DataFormat.IsShadow = true;

    // Save the workbook
    const outputFileName = 'PivotChartSeriesFormat.xlsx';
    workbook.SaveToFile(outputFileName);
    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>Format PivotChart Series</h1>
      <button onClick={formatPivotChartSeries}>
        Generate
      </button>
    </div>
  );
}

export default App;

Pivot chart series format set with Spire.XLS for JavaScript

Pivot chart series format set with Spire.XLS for JavaScript


FAQ

How to refresh a pivot chart to show the latest data?

Cause: A pivot chart is created based on a pivot table. After modifying the data source of the pivot table, the chart does not automatically sync the updates.

Solution: After modifying the data source, use the Cache.IsRefreshOnLoad property to make the pivot table refresh automatically when the file opens, so the pivot chart is updated accordingly:

// Get the pivot table
let pivotTable = sheet.PivotTables.get(0);
// Refresh the pivot table automatically when the file opens
pivotTable.Cache.IsRefreshOnLoad = true;

Why does my pivot chart not show any data?

Cause: The series of a pivot chart come from the summarized results of a pivot table. If the pivot table has not been calculated, or the pivot chart was not correctly associated with the pivot table, the chart may appear blank.

Solution: Call the CalculateData() method after creating the pivot table to calculate the results, and correctly associate the pivot table via the pivotTable parameter when creating the pivot chart:

// Calculate the data of the pivot table
pivotTable.CalculateData();

// Create a pivot chart based on the pivot table
let chart = sheet.Charts.Add({ pivotChartType: xlsModule.ExcelChartType.ColumnClustered, pivotTable: pivotTable });

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 office automation workflows, you often need to batch-extract product images from Excel reports, replace outdated logos, or export a specific image individually. Spire.XLS for JavaScript handles all of these image operations directly in the browser via WebAssembly, using a virtual file system (VFS) to manage input and output files — no backend server is required.

This article covers three core features:

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.


Extract All Images from a Worksheet

Batch-extracting all images from a worksheet is useful for backing up embedded images in reports, migrating product materials, and similar scenarios. The process consists of three steps: iterate over the Worksheet.Pictures collection, call the Picture.Save method on each image to save it to the VFS, then read each file and trigger a browser download.

function App() {
  const extractAllImages = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the Excel file into VFS
    const inputFileName = 'ReadImages.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);

    // Iterate through all pictures in the worksheet and export each one
    for (let i = 0; i < sheet.Pictures.Count; i++) {
      const pic = sheet.Pictures.get(i);
      const outputFileName = `Image-${i + 1}.png`;
      pic.Picture.Save(outputFileName);

      // Read the exported image file from VFS and trigger download
      const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
      const blob = new Blob([fileArray], { type: "image/png" });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = outputFileName;
      a.click();
      URL.revokeObjectURL(url);
    }

    // Release resources
    workbook.Dispose();
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Extract All Images from Worksheet</h1>
      <button onClick={extractAllImages}>
        Extract All Images
      </button>
    </div>
  );
}

export default App;

Image files extracted and downloaded from the worksheet in batch

Image files extracted and downloaded from the worksheet in batch


Extract a Specific Image

There are two common ways to extract a specific image from a worksheet: retrieve it directly by index, or iterate through pictures by name to find a match. The index approach suits scenarios where the picture position is known (for example, the first picture), while the name approach is better when you know the picture identifier in advance. The process consists of two steps: first locate the target image by index or name, then export it as a local file.

function App() {
  const extractImage = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the Excel file into VFS
    const inputFileName = 'ReadImages.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);

    // Method 1: Extract by index (e.g., extract the second picture)
    const pic = sheet.Pictures.get(1);
    const outputFileName = 'ExtractByIndex.png';

    // // Method 2: Iterate through pictures by name to find a match
    // let pic = null;
    // const targetName = 'SpireXLS';
    // for (let i = 0; i < sheet.Pictures.Count; i++) {
    //   if (sheet.Pictures.get(i).Name === targetName) {
    //     pic = sheet.Pictures.get(i);
    //     break;
    //   }
    // }
    // const outputFileName = 'ExtractByName.png';

    // Save the picture to VFS and trigger download
    pic.Picture.Save(outputFileName);
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: "image/png" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);

    workbook.Dispose();
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Extract a Specific Image</h1>
      <button onClick={extractImage}>
        Extract Image
      </button>
    </div>
  );
}

export default App;

Specific image extracted and downloaded by index or name

Specific image extracted and downloaded by index or name


Replace an Existing Image in a Worksheet

Replacing an existing image in a worksheet is a common requirement when updating report logos, changing product display images, and in similar scenarios. The approach is to first retrieve the position and size information of the target image, then delete it via XlsShape.Convert, and finally insert a new image at the same position, setting the new image's size and offsets to match the original.

function App() {
  const replaceImage = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

    // Check if the module is ready
    if (!xlsModule) {
      alert('Spire.Xls is not ready yet');
      return;
    }

    // Load the Excel file and the new image into VFS
    const inputFileName = 'ReadImages.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}data/`);
    const newImageFile = 'Logo.png';
    await window.spire.FetchFileToVFS(newImageFile, '', `${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);

    // Get the first picture and its position and size information
    const oldPic = sheet.Pictures.get(0);
    const topRow = oldPic.TopRow;
    const leftColumn = oldPic.LeftColumn;
    const leftColumnOffset = oldPic.LeftColumnOffset;
    const topRowOffset = oldPic.TopRowOffset;
    const width = oldPic.Width;
    const height = oldPic.Height;

    // Delete the original picture
    xlsModule.XlsShape.Convert(oldPic).Remove();

    // Insert the new picture at the same position
    let picture = sheet.Pictures.Add({ topRow: topRow, leftColumn: leftColumn, fileName: newImageFile });

    // Set the new picture's size and offsets to match the original
    picture.Width = width;
    picture.Height = height;
    picture.LeftColumnOffset = leftColumnOffset;
    picture.TopRowOffset = topRowOffset;

    const outputFileName = 'ReplaceImage-out.xlsx';
    // Save the modified workbook
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
    // Release resources
    workbook.Dispose();

    // Read the generated 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>Replace Image in Worksheet</h1>
      <button onClick={replaceImage}>
        Replace Image
      </button>
    </div>
  );
}

export default App;

The Excel worksheet after the image is replaced

The Excel worksheet after the image is replaced


FAQ

Extracted images cannot be opened or the format is incorrect

Cause: The correct file extension was not specified when saving the image, or the MIME type does not match the image format.

Solution: Make sure the file extension used in the Picture.Save method matches the actual image format. If the image is in PNG format, the file extension should be .png; if it is in JPEG format, use .jpg. The Blob type used for the download should be set accordingly:

// PNG format
const blob = new Blob([fileArray], { type: "image/png" });

// JPEG format
const blob = new Blob([fileArray], { type: "image/jpeg" });

The position or size of the image changes after replacement

Cause: The position and size properties of the original image were not recorded before deletion, so the new image cannot be precisely aligned to the original position or retain its original size.

Solution: Save the position properties such as TopRow, LeftColumn, LeftColumnOffset, TopRowOffset and the size properties Width, Height before deleting the image. After inserting the new image, set these properties on the new picture so it matches the original:

// Insert the new picture (specify the row and column position)
let picture = sheet.Pictures.Add({ topRow: topRow, leftColumn: leftColumn, fileName: newImageFile });

// Set size and offsets to match the original
picture.Width = width;
picture.Height = height;
picture.LeftColumnOffset = leftColumnOffset;
picture.TopRowOffset = topRowOffset;

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.

OFD (Open Fixed-layout Document) is a national standard fixed-layout document format widely used in e-invoices, e-certificates, administrative approvals, and other government and financial scenarios. OFD describes document structure based on XML, offering advantages such as independent control and information security. Meanwhile, PDF remains indispensable as an internationally recognized document format for cross-platform distribution. Real-world business often requires flexible switching between the two formats: receiving OFD-format e-invoices and converting them to PDF for printing and distribution, or converting existing PDF contracts to OFD to meet government platform upload requirements.

Spire.PDF for JavaScript performs bidirectional conversion between PDF and OFD entirely in the browser via WebAssembly, managing input and output files through a virtual file system (VFS) with no backend server required.

This article covers two core features:

For installation and project setup, refer to Integrating Spire.PDF for JavaScript in a React Project. The examples below assume Spire.PDF is installed and the WebAssembly module is initialized.


Convert PDF to OFD

The core of PDF-to-OFD conversion is to re-encode the page content, fonts, and graphics elements from a PDF document into an XML description structure compliant with the OFD standard. Spire.PDF for JavaScript accomplishes this in one step through the PdfDocument object's SaveToFile method with the FileFormat.OFD enum value, eliminating the need to handle underlying format differences manually.

function App() {
  const convertToOFD = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check if the WASM module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load fonts and PDF file into VFS
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'TemplateIntroduction-en.pdf';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create PdfDocument object and load the PDF document
    let doc = new pdfModule.PdfDocument();
    doc.LoadFromFile(inputFileName);

    // Define the output file name for OFD format
    const outputFileName = 'OutputOFD.ofd';

    // Save as OFD format
    doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.OFD });
    doc.Close();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/ofd' });
    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>Convert PDF To OFD</h1>
      <button onClick={convertToOFD}>
        Generate
      </button>
    </div>
  );
}

export default App;

OFD output generated after conversion via SaveToFile with FileFormat.OFD

OFD output generated after conversion via SaveToFile with FileFormat.OFD


Convert OFD to PDF

OFD-to-PDF conversion is a common requirement in government electronic document distribution scenarios. Spire.PDF for JavaScript provides the OfdConverter component, which is specifically designed to parse OFD fixed-layout documents and export them as standard PDF files while preserving the original document's layout and visual appearance.

function App() {
  const convertOFDToPDF = async () => {
    // Get the Spire.PDF WASM module
    const pdfModule = window.wasmModule?.spirepdf;

    // Check if the WASM module is ready
    if (!pdfModule) {
      alert('Spire.PDF is not ready yet');
      return;
    }

    // Load fonts and OFD file into VFS
    await window.spire.FetchFileToVFS('Arial.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
    const inputFileName = 'Invoice_EN.ofd';
    await window.spire.FetchFileToVFS(inputFileName, "", `${process.env.PUBLIC_URL}/data/`);

    // Create OfdConverter object and pass the OFD file path
    let converter = new pdfModule.OfdConverter(inputFileName);
    
    // Define the output file name for PDF format
    const outputFileName = 'OutputPDF.pdf';

    // Convert to PDF format
    converter.ToPdf(outputFileName);
    converter.Dispose();

    // Read the converted file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'application/pdf' });
    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>Convert OFD To PDF</h1>
      <button onClick={convertOFDToPDF}>
        Generate
      </button>
    </div>
  );
}

export default App;

Standard PDF output generated after conversion via OfdConverter

Standard PDF output generated after conversion via OfdConverter


FAQ

Can encrypted PDFs be converted to OFD?

Password-protected encrypted PDFs cannot be saved as OFD directly via SaveToFile — the document must be decrypted first.

Solution: Provide the password when loading the PDF via the second parameter of LoadFromFile, then save as OFD:

// Load a password-protected PDF document
let doc = new pdfModule.PdfDocument();
doc.LoadFromFile(inputFileName, "password");

// Save as OFD format
doc.SaveToFile({ fileName: outputFileName, fileFormat: pdfModule.FileFormat.OFD });
doc.Close();

Garbled text in the converted OFD document

OFD relies on font embedding to ensure consistent cross-platform rendering. If the input PDF uses non-embedded fonts and the corresponding font files are not loaded in the VFS, text may appear garbled after conversion.

Solution: Make sure the required TrueType font files (e.g., ARIALUNI.TTF) are loaded into the /Library/Fonts/ directory in VFS before calling the conversion. ARIALUNI.TTF covers common CJK characters and is the recommended font for ensuring conversion quality.


Get a Free License

Spire.PDF for JavaScript offers a 30-day full-featured free trial license with no functional limitations. Apply here to evaluate before purchasing.

Data labels are an essential element of Excel charts for displaying detailed information about data points, such as values, series names, and category names. 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 required. It provides a complete API for controlling data label display content, font formatting, number format, position, background, borders, and other appearance properties.

This article covers two core features:

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.


Set Data Label Content and Font

Data labels can display various types of information, including values, series names, category names, and legend keys. With Spire.XLS for JavaScript, you can flexibly control the display content of data labels and customize their font styles to make the chart information clearer and more readable. The steps are as follows:

  1. Create a Workbook object and get the default worksheet.
  2. Populate the worksheet with category labels and numeric data for the chart.
  3. Add a chart using sheet.Charts.Add() and set the chart type.
  4. Configure the chart's data range, position, and title.
  5. Enable data label display content (values, series names, category names) via the DataLabels property.
  6. Set data label font properties (font name, size, color, bold, etc.).
  7. Save the workbook to an Excel file using SaveToFile().

Below is a complete code example demonstrating how to set chart data label content and font in React:

function App() {
  const setDataLabelContentAndFont = 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;
    }

    // Create a new workbook and get the default worksheet
    const workbook = new xlsModule.Workbook();
    let sheet = workbook.Worksheets.get(0);
    sheet.Name = "DataLabelDemo";

    // Populate chart data
    sheet.Range.get("A1").Value = "Month";
    sheet.Range.get("A2").Value = "Jan";
    sheet.Range.get("A3").Value = "Feb";
    sheet.Range.get("A4").Value = "Mar";
    sheet.Range.get("A5").Value = "Apr";
    sheet.Range.get("A6").Value = "May";
    sheet.Range.get("A7").Value = "Jun";

    sheet.Range.get("B1").Value = "Sales";
    sheet.Range.get("B2").NumberValue = 25;
    sheet.Range.get("B3").NumberValue = 18;
    sheet.Range.get("B4").NumberValue = 8;
    sheet.Range.get("B5").NumberValue = 13;
    sheet.Range.get("B6").NumberValue = 22;
    sheet.Range.get("B7").NumberValue = 28;

    // Add a line chart and set its data range
    let chart = sheet.Charts.Add({ chartType: xlsModule.ExcelChartType.LineMarkers });
    chart.DataRange = sheet.Range.get("B1:B7");
    chart.SeriesDataFromRange = false;

    // Set the chart position
    chart.TopRow = 5;
    chart.BottomRow = 26;
    chart.LeftColumn = 2;
    chart.RightColumn = 11;

    // Configure chart title
    chart.ChartTitle = "Data Labels Demo";
    chart.ChartTitleArea.IsBold = true;
    chart.ChartTitleArea.Size = 12;

    // Bind category labels
    let cs1 = chart.Series.get(0);
    cs1.CategoryLabels = sheet.Range.get("A2:A7");

    // Set data label display content: show values, series names, and category names
    cs1.DataPoints.DefaultDataPoint.DataLabels.HasValue = true;
    cs1.DataPoints.DefaultDataPoint.DataLabels.HasSeriesName = true;
    cs1.DataPoints.DefaultDataPoint.DataLabels.HasCategoryName = true;

    // Set data label delimiter
    cs1.DataPoints.DefaultDataPoint.DataLabels.Delimiter = ". ";

    // Customize data label font styles
    cs1.DataPoints.DefaultDataPoint.DataLabels.Size = 9;
    cs1.DataPoints.DefaultDataPoint.DataLabels.Color = xlsModule.Color.get_Red();
    cs1.DataPoints.DefaultDataPoint.DataLabels.FontName = "Calibri";
    cs1.DataPoints.DefaultDataPoint.DataLabels.IsBold = true;

    // Save the workbook
    const outputFileName = 'DataLabelContentAndFont.xlsx';
    workbook.SaveToFile(outputFileName);
    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>Set Data Label Content and Font</h1>
      <button onClick={setDataLabelContentAndFont}>
        Generate
      </button>
    </div>
  );
}

export default App;

Data label content and font set with Spire.XLS for JavaScript

Data label content and font set with Spire.XLS for JavaScript


Adjust Data Label Position and Appearance

Beyond display content and font styles, the position and appearance of data labels are also important aspects of chart visual enhancement. Spire.XLS for JavaScript supports adjusting the display position of data labels through the DataLabelPositionType enumeration, and allows you to set fill colors, border styles, and shadow effects for data labels. The steps are as follows:

  1. Create a Workbook object and load an existing Excel file containing a chart.
  2. Get the worksheet via workbook.Worksheets.get().
  3. Get the chart object using sheet.Charts.get().
  4. Iterate through the chart's data series and set the data label position using DataLabels.Position.
  5. Set a background fill color for the data labels via FrameFormat.Fill.
  6. Set border color and style for the data labels via FrameFormat.Border.
  7. Add shadow effects to data labels via FrameFormat.Shadow (type, color, transparency, size, blur, angle, and distance).
  8. Save the workbook to an Excel file using SaveToFile().

Below is a complete code example demonstrating how to adjust chart data label position and appearance in React:

function App() {
  const setDataLabelPositionAndAppearance = 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 sample file into the virtual file system (VFS)
    let excelFileName = 'SampleChart.xlsx';
    await window.spire.FetchFileToVFS(excelFileName, '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the existing file
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: excelFileName });

    // Get the first worksheet
    let sheet = workbook.Worksheets.get(0);

    // Get the first chart
    let chart = sheet.Charts.get(0);

    // Iterate through all data series and adjust data label position and appearance
    for (let i = 0; i < chart.Series.Count; i++) {
      let cs = chart.Series.get(i);
      // Set data point marker style and size to make data points more prominent
      cs.DataFormat.MarkerSize = 6;
      cs.DataFormat.MarkerStyle = xlsModule.ChartMarkerType.Circle;
      cs.DataFormat.MarkerForegroundColor = xlsModule.Color.get_Blue();
      cs.DataFormat.MarkerBackgroundColor = xlsModule.Color.get_White();
      
      let dataLabels = cs.DataPoints.DefaultDataPoint.DataLabels;

      // Enable value labels
      dataLabels.HasValue = true;

      // Set data label position
      dataLabels.Position = xlsModule.DataLabelPositionType.Right;

      // Set data label font color and size
      dataLabels.Color = xlsModule.Color.get_Blue();
      dataLabels.Size = 10;

      // Set pink fill background
      dataLabels.FrameFormat.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
      dataLabels.FrameFormat.ForeGroundColor = xlsModule.Color.get_Pink();

      // Set red border
      dataLabels.FrameFormat.Border.Pattern = xlsModule.ChartLinePatternType.Solid;
      dataLabels.FrameFormat.Border.Color = xlsModule.Color.get_Red();

      // Set yellow shadow effect
      dataLabels.FrameFormat.Shadow.ShadowOuterType = xlsModule.XLSXChartShadowOuterType.OffsetDiagonalBottomLeft;
      dataLabels.FrameFormat.Shadow.Color = xlsModule.Color.get_Yellow();
      dataLabels.FrameFormat.Shadow.Transparency = 0;
      dataLabels.FrameFormat.Shadow.Size = 10;
      dataLabels.FrameFormat.Shadow.Blur = 2;
      dataLabels.FrameFormat.Shadow.Angle = 45;
      dataLabels.FrameFormat.Shadow.Distance = 8;
    }

    // Save the workbook
    const outputFileName = 'DataLabelPositionAndAppearance.xlsx';
    workbook.SaveToFile(outputFileName);
    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>Set Data Label Position and Appearance</h1>
      <button onClick={setDataLabelPositionAndAppearance}>
        Generate
      </button>
    </div>
  );
}

export default App;

Data label position and appearance adjusted with Spire.XLS for JavaScript

Data label position and appearance adjusted with Spire.XLS for JavaScript


FAQ

How to modify the label content of a specific data point instead of the entire series?

Cause: DefaultDataPoint.DataLabels applies to all data points in a series and cannot control individual data points separately.

Solution: Use DataPoints.get(index) to access a specific data point and set its label:

// Modify the label text of the third data point
chart.Series.get(0).DataPoints.get(2).DataLabels.Text = "Peak";
chart.Series.get(0).DataPoints.get(2).DataLabels.HasValue = false;

How to set number format for data labels (decimal places, currency symbols)

Cause: The number format of data labels matches the cell format by default, but sometimes needs to be controlled independently.

Solution: Use the DataLabels.NumberFormat property to customize the number format:

// Show two decimal places
dataLabels.NumberFormat = "0.00";
// Display as percentage
dataLabels.NumberFormat = "0.0%";
// Display with currency symbol
dataLabels.NumberFormat = "$#,##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.

In daily office work, data often needs to be exchanged between Excel spreadsheets and plain text (TXT) files. 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 flexible APIs for controlling conversion parameters such as delimiters and encoding formats.

With Spire.XLS for JavaScript, you can export Excel worksheet data as structured text files, or import delimited text files to create fully formatted Excel workbooks. This makes data migration between different applications more convenient and efficient.

This article covers two core features:

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.


Convert Excel Worksheet Data to TXT

Exporting Excel data as a plain text file makes it convenient for further processing or analysis in other applications. With Spire.XLS for JavaScript, you can save the contents of a specified worksheet as a TXT file, with flexible control over the field separator and character encoding. The steps are as follows:

  • Create a Workbook object and load an existing Excel file.
  • Retrieve a specific worksheet via workbook.Worksheets.get(index).
  • Call the worksheet's SaveToFile() method, specifying the output filename, separator, and encoding.
  • Dispose of the workbook resources, read the result file from VFS, and trigger the download.

Below is a complete code example demonstrating how to convert Excel to TXT in React:

function App() {
  const convertToText = 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 sample file into VFS
    await window.spire.FetchFileToVFS('Sample.xlsx', '', `${process.env.PUBLIC_URL}data/`);

    // Create a workbook object and load the Excel file
    const workbook = new xlsModule.Workbook();
    workbook.LoadFromFile({ fileName: 'Sample.xlsx' });

    // Get the first worksheet
    let sheet = workbook.Worksheets.get(0);

    // Save the worksheet as a TXT file with space separator and UTF-8 encoding
    const outputFileName = 'ExcelToTxt.txt';
    sheet.SaveToFile({
      fileName: outputFileName,
      separator: " ",
      encoding: xlsModule.Encoding.get_UTF8()
    });
    workbook.Dispose();

    // Read the file from VFS and trigger download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    a.click();
    URL.revokeObjectURL(url);
  };

  return (
    <div style={{ textAlign: 'center', height: '300px' }}>
      <h1>Convert Excel to TXT</h1>
      <button onClick={convertToText}>
        Generate
      </button>
    </div>
  );
}

export default App;

Excel converted to TXT with Spire.XLS for JavaScript

Excel converted to TXT with Spire.XLS for JavaScript


Convert TXT File to Excel Workbook

Importing a delimited text file into an Excel spreadsheet allows you to take full advantage of Excel's formatting, calculation, and charting capabilities. Spire.XLS for JavaScript supports TXT-to-Excel conversion by reading the text file content and writing data to the workbook cell by cell. Formatting such as bold headers can also be applied during the process. The steps are as follows:

  • Load the font file and TXT sample file into the VFS.
  • Read the TXT file content from VFS, split it by lines, and parse the cell data for each line.
  • Create a Workbook object, iterate through the data array, and write data to worksheet cells row by row and column by column.
  • Apply bold styling to the header row and call AllocatedRange.AutoFitColumns() to auto-fit column widths.
  • Save the workbook as an Excel file and trigger the download.

Below is a complete code example demonstrating how to convert TXT to Excel in React:

function App() {
  const convertToExcel = 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', '', `${process.env.PUBLIC_URL}font/`);

    // Load the TXT file into VFS
    await window.spire.FetchFileToVFS('Sample.txt', '', `${process.env.PUBLIC_URL}data/`);

    // Read the text file content from VFS
    const txtData = window.dotnetRuntime.Module.FS.readFile('Sample.txt');
    const text = typeof txtData === 'string' ? txtData : new TextDecoder('utf-8').decode(txtData);

    // Split by lines, compatible with \r\n and \n
    const lines = text.trim().split(/\r?\n/);

    // Parse each line of data (try tab delimiter first, then fallback to other delimiters)
    const data = [];
    for (const line of lines) {
      const trimmed = line.trim();
      if (!trimmed) continue;
      let cells = trimmed.split('\t');
      if (cells.length === 1) {
        cells = trimmed.split(/\s+/);
      }
      data.push(cells);
    }

    // Create a Workbook object
    const workbook = new xlsModule.Workbook();

    // Get the first worksheet
    const sheet = workbook.Worksheets.get(0);

    // Iterate through rows and columns in the data array and write to cells
    for (let row = 0; row < data.length; row++) {
      for (let col = 0; col < data[row].length; col++) {
        const cell = sheet.get_Item(row + 1, col + 1);
        cell.Value = data[row][col];
        // Bold the header row
        if (row === 0) {
          cell.Style.Font.IsBold = true;
        }
      }
    }

    // Auto-fit column widths
    sheet.AllocatedRange.AutoFitColumns();

    // Save the workbook and release resources
    const outputFileName = 'TxtToExcel.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });
    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>Convert TXT to Excel</h1>
      <button onClick={convertToExcel}>
        Generate
      </button>
    </div>
  );
}

export default App;

TXT converted to Excel with Spire.XLS for JavaScript

TXT converted to Excel with Spire.XLS for JavaScript


FAQ

How to handle encoding issues during conversion?

Cause: The TXT file in this example uses UTF-8 encoding. If the TXT file uses a different encoding format (such as GBK, GB2312, etc.), decoding it directly with TextDecoder('utf-8') will result in garbled text.

Solution: Specify the corresponding encoding type in the TextDecoder constructor parameter based on the actual encoding of the TXT file:

// UTF-8 encoding
const text = new TextDecoder('utf-8').decode(txtData);

// GBK encoding
const text = new TextDecoder('gbk').decode(txtData);

// GB2312 encoding
const text = new TextDecoder('gb2312').decode(txtData);

// UTF-16 encoding
const text = new TextDecoder('utf-16').decode(txtData);

How to handle TXT files with different delimiters?

Cause: TXT files may use different delimiters such as tabs (\t), spaces, commas (,), semicolons (;), etc. Choosing the wrong delimiter can lead to data parsing errors.

Solution: In JavaScript, you can specify different delimiters by modifying the parameter of the split() method:

// Tab delimiter
let cells = trimmed.split('\t');

// Comma delimiter
let cells = trimmed.split(',');

// Semicolon delimiter
let cells = trimmed.split(';');

// Regular expression: split by one or more whitespace characters (spaces, tabs, etc.)
let cells = trimmed.split(/\s+/);

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.

page 13