Add Hyperlinks to Shapes in Excel with JavaScript in React

A shape in Excel is usually there to point at something: the arrow on a diagram, the triangle that flags a number, the cloud that circles an area. Give it a hyperlink and the drawing becomes an entry point a reader can click. A shape, like a picture, is not a cell, and its hyperlink lives on the shape object itself, so both setting and reading one go through the worksheet's shape collection rather than its cell hyperlink collection. Spire.XLS for JavaScript does this in the browser on WebAssembly, handling input and output files through a virtual file system (VFS) with no backend service.

This article covers two core feature points:

For installation and project setup, see Integrating Spire.XLS for JavaScript in a React Project. The examples below assume Spire.XLS is installed and the WebAssembly module has been initialised.


Set a hyperlink on a shape

Setting a hyperlink on a shape is what turns a drawing into a clickable entry point: a reader who clicks the shape on the worksheet opens the address it points at. The link belongs to the shape itself rather than to a cell, so the shape has to be taken from the worksheet's shape collection first, and the address handed to its own link object. The steps are:

  1. Load the font and the test data file into the VFS.
  2. Load the workbook with workbook.LoadFromFile.
  3. Add the shapes into the space left for them with sheet.PrstGeomShapes.AddPrstGeomShape.
  4. Take the shape count from sheet.PrstGeomShapes.Count and walk every shape on the worksheet with it.
  5. Take each shape's link object from its HyLink property and write the address into its Address.
  6. Save the workbook with workbook.SaveToFile.
  7. Dispose of the workbook with workbook.Dispose to free resources.

The complete code example below shows how to set a hyperlink on a shape in Excel in React:

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

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

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

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

    // take the first worksheet and add the three shapes into the space left for them
    const sheet = workbook.Worksheets.get(0);
    const shapes = sheet.PrstGeomShapes;
    shapes.AddPrstGeomShape(10, 1, 90, 60, xlsModule.PrstGeomShapeType.Triangle);
    shapes.AddPrstGeomShape(10, 3, 90, 60, xlsModule.PrstGeomShapeType.CurvedRightArrow);
    shapes.AddPrstGeomShape(10, 5, 90, 60, xlsModule.PrstGeomShapeType.Cloud);

    // set a hyperlink on each shape in turn
    const addresses = [
      'https://www.e-iceblue.com/Introduce/xls-for-javascript.html',
      'https://www.e-iceblue.com/Buy/Spire.XLS-JavaScript.html',
      'https://www.e-iceblue.com/Download/Spire-Office-JavaScript.html',
    ];
    for (let i = 0; i < shapes.Count; i++) {
      shapes.get(i).HyLink.Address = addresses[i];
    }

    // save the workbook
    const outputFileName = 'ShapeHyperlink.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, fileFormat: xlsModule.FileFormat.Version2010 });

    // dispose of the workbook to free resources
    workbook.Dispose();

    // read the result file from the VFS and start 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>Add Hyperlinks to Shapes in Excel</h1>
      <button id="shape-hyperlink" onClick={shapeHyperlink}>Set a hyperlink on the shape</button>
    </div>
  );
}

export default App;

After running, the effect of setting a hyperlink on a shape:

Set a hyperlink on a shape in Excel


Read the hyperlink from a shape

Reading the hyperlink off a shape is how a finished sheet is checked over: whether every shape carries a link, and whether they point at the right addresses. The addresses that come back are written out as a text file, which makes them easy to line up against a list of links. Shape hyperlinks are not kept in the cell hyperlink collection, so the shapes have to be taken from the worksheet one by one, and each one asked for its own link object. The steps are:

  1. Load the font and the test data file into the VFS.
  2. Load the workbook with workbook.LoadFromFile.
  3. Take the shape count from sheet.PrstGeomShapes.Count and walk every shape on the worksheet with it.
  4. Take this shape's link object from its HyLink property.
  5. Read the target address from the link object's Address, collecting the addresses as you go.
  6. Write the collected addresses into a text file with FS.writeFile, one address per line.
  7. Dispose of the workbook with workbook.Dispose to free resources.

The complete code example below shows how to read the hyperlink from a shape in Excel in React:

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

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

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

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

    // walk the shapes of the worksheet and read the hyperlink off each one
    const sheet = workbook.Worksheets.get(0);
    const shapes = sheet.PrstGeomShapes;
    const addresses = [];
    for (let i = 0; i < shapes.Count; i++) {
      addresses.push(shapes.get(i).HyLink.Address);
    }

    // write the addresses that were read into a text file
    const outputFileName = 'ReadShapeHyperlink.txt';
    window.dotnetRuntime.Module.FS.writeFile(outputFileName, addresses.join('\n'));

    // dispose of the workbook to free resources
    workbook.Dispose();

    // read the result file from the VFS and start 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>Add Hyperlinks to Shapes in Excel</h1>
      <button id="read-shape-hyperlink" onClick={readShapeHyperlink}>Read the hyperlink from the shape</button>
    </div>
  );
}

export default App;

After running, the effect of reading the hyperlink from a shape:

Read the hyperlink from a shape in Excel


FAQ

Why does a shape's hyperlink not show up in sheet.HyperLinks?

Cause: sheet.HyperLinks collects cell hyperlinks only. A shape is not a cell; it belongs to the worksheet's shape collection, and the link hangs on the shape object's HyLink.

Solution: Go through the shape collection. In this example, after a hyperlink was set on the shapes, sheet.HyperLinks.Count was still 0, and it was still 0 after the file was saved and opened again. Read a shape's link with sheet.PrstGeomShapes.get(i).HyLink.Address.

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.