Add Arrow Connectors in Excel in JavaScript (React)

2026-09-23 07:30:44 Allen Yang
AI Summarize:
ChatGPT
ChatGPT
Claude
Grok
Perplexity
Quick
Quick
Concise overview
Highlights
Key takeaways
Detailed
Structured explanation
Brief
One sentence summary
Summarize |

Inserting arrow-tipped lines and directional connectors in an Excel worksheet in the browser with Spire.XLS for JavaScript

A line between two boxes in a flowchart says "these are related". An arrow from one to the other says "this one comes first". That distinction — direction — is what separates a connector from a decoration, and it is the one thing the basic Lines.AddLine() API cannot do on both ends. A process flow needs an arrow leaving each step; a cause-and-effect diagram needs arrows pointing in; a comparison sometimes needs double-headed arrows to show a bidirectional link. None of these are possible with a single EndArrowHeadStyle.

Spire.XLS for JavaScript provides sheet.TypedLines.AddLine() for exactly this case. It positions lines by pixel coordinates instead of row and column, and it accepts BeginArrowHeadStyle and EndArrowHeadStyle independently — so a line can carry an arrow on one end, both ends, or neither. The engine runs in the browser on WebAssembly, with files moving through a virtual file system (VFS) and no backend involved.

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


Direction changes everything

Three diagrams, three different directional requirements, and the same line API handles all of them:

Diagram type Arrow configuration What it communicates
Process flow Arrow on the end only Sequential execution — step A leads to step B
Causal chain Arrow on the end only, multiple lines in sequence Cause produces effect, which produces the next effect
Bidirectional link Arrow on both ends Mutual relationship — A affects B and B affects A
Annotation pointer Arrow on the end, no arrow on the beginning A label points at the cell it describes

The arrowhead style itself also carries meaning. A solid filled arrow (LineArrow) reads as a definite, committed connection. An open arrow (LineArrowOpen) reads as a looser, less certain one — common in data-flow diagrams where the direction is known but the mechanism is not specified.


Prerequisites

You need a React project with Spire.XLS for JavaScript installed and the WebAssembly module initialized, reachable at window.wasmModule.spirexls. The sample loads a font into the VFS and saves with the Excel 2010 version flag.


TypedLines vs Lines: what is different

sheet.Lines.AddLine() and sheet.TypedLines.AddLine() are two separate APIs for two separate needs. The differences are structural, not cosmetic:

Lines.AddLine() TypedLines.AddLine()
Positioning Row and column coordinates Pixel coordinates (Top, Left)
Size width and height in the constructor Width and Height as properties
Arrow on end EndArrowHeadStyle EndArrowHeadStyle
Arrow on beginning Not supported BeginArrowHeadStyle
Line type Set via lineShapeType in constructor Set via LineShapeType property
Best for Simple line shapes aligned to cells Directional connectors with precise placement

The beginning-arrow support is the most consequential difference. With Lines.AddLine(), a line can have an arrowhead at its end but not at its start — which is enough for a one-way flow but not for a bidirectional link. TypedLines.AddLine() removes that constraint.

For basic line shapes without arrows, Insert Line Shapes in Excel in JavaScript (React) covers the Lines.AddLine() API.


Pixel-precise positioning

TypedLines.AddLine() places lines using Top and Left in pixels, with Width and Height controlling the extent:

let line = sheet.TypedLines.AddLine();
line.Top = 10;     // 10 pixels from the top of the sheet
line.Left = 20;    // 20 pixels from the left
line.Width = 100;  // 100 pixels wide
line.Height = 0;   // 0 height — a horizontal line

A Height of 0 produces a horizontal line; a Width of 0 produces a vertical one. Setting both to non-zero values produces a diagonal or a bent connector, depending on the LineShapeType.

The shift from row-and-column to pixel coordinates matters most when lines need to connect specific points inside cells — the middle of a merged range, the edge of a border — rather than aligning with cell boundaries. Pixel positioning lets you compute the exact start and end from the layout you know, rather than estimating which row and column comes closest.


Arrow combinations

With BeginArrowHeadStyle and EndArrowHeadStyle set independently, four combinations cover the common cases:

Begin End Visual Meaning
LineNoArrow LineArrow One-way direction: A leads to B
LineArrow LineArrow Bidirectional: A and B affect each other
LineArrow LineNoArrow Reverse one-way: B leads to A (rare, but useful for right-to-left layouts)
LineNoArrow LineNoArrow No direction: a plain connector (use Lines.AddLine() instead for simplicity)

The arrow style can also be LineArrowOpen — an open V-shape rather than a filled triangle — on either end. Mixing styles on the two ends is valid: a filled arrow on one end and an open arrow on the other communicates that one direction is definite and the other is tentative.


Insert arrow-tipped lines

The example inserts six arrow-tipped lines into a fresh worksheet, covering the common combinations: a double-arrow line, a single-arrow line, an elbow arrow connector, an elbow double-arrow connector, a curved arrow connector, and a curved double-arrow connector. The steps are:

  1. Create a Workbook object and get the first worksheet.
  2. Call Worksheet.TypedLines.AddLine() to create each line.
  3. Set line position through Top, Left, Width, and Height (in pixels).
  4. Set arrow styles on both ends through BeginArrowHeadStyle and EndArrowHeadStyle.
  5. Specify the line type through LineShapeType (straight, elbow, curved, etc.).
  6. Save the workbook with Workbook.SaveToFile().
function App() {
  const addArrowLines = async () => {
    // Get the Spire.XLS WASM module
    const xlsModule = window.wasmModule?.spirexls;

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

    // Load the font into the VFS for text measurement and column auto-fit
    await window.spire.FetchFileToVFS('ARIAL.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

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

    // Add a double-arrow line - solid blue
    let line = sheet.TypedLines.AddLine();
    line.Top = 10;
    line.Left = 20;
    line.Width = 100;
    line.Height = 0;
    line.Color = xlsModule.Color.get_Blue();
    line.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
    line.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;

    // Add a single-arrow line - solid red
    let line_1 = sheet.TypedLines.AddLine();
    line_1.Top = 50;
    line_1.Left = 30;
    line_1.Width = 100;
    line_1.Height = 100;
    line_1.Color = xlsModule.Color.get_Red();
    line_1.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineNoArrow;
    line_1.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;

    // Add an elbow arrow connector
    let line3 = sheet.TypedLines.AddLine();
    line3.LineShapeType = xlsModule.LineShapeType.ElbowLine;
    line3.Width = 30;
    line3.Height = 50;
    line3.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
    line3.Top = 100;
    line3.Left = 50;

    // Add an elbow double-arrow connector
    let line2 = sheet.TypedLines.AddLine();
    line2.LineShapeType = xlsModule.LineShapeType.ElbowLine;
    line2.Width = 50;
    line2.Height = 50;
    line2.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
    line2.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrow;
    line2.Left = 120;
    line2.Top = 100;

    // Add a curved arrow connector
    line3 = sheet.TypedLines.AddLine();
    line3.LineShapeType = xlsModule.LineShapeType.CurveLine;
    line3.Width = 30;
    line3.Height = 50;
    line3.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrowOpen;
    line3.Top = 100;
    line3.Left = 200;

    // Add a curved double-arrow connector
    line2 = sheet.TypedLines.AddLine();
    line2.LineShapeType = xlsModule.LineShapeType.CurveLine;
    line2.Width = 30;
    line2.Height = 50;
    line2.EndArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrowOpen;
    line2.BeginArrowHeadStyle = xlsModule.ShapeArrowStyleType.LineArrowOpen;
    line2.Left = 250;
    line2.Top = 100;

    // Save the workbook
    const outputFileName = 'AddArrowLines.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: xlsModule.ExcelVersion.Version2010 });

    // Release resources
    workbook.Dispose();

    // Read the saved 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>Add Arrow Lines</h1>
      <button onClick={addArrowLines}>Start</button>
    </div>
  );
}

export default App;

Six arrow-tipped lines: double-arrow, single-arrow, elbow arrow, elbow double-arrow, curved arrow, and curved double-arrow

Insert arrow-tipped lines

Note the reuse of the line3 and line2 variables in the second half of the function. Each call to TypedLines.AddLine() returns a new line object that has already been added to the worksheet — the variable is a handle for setting properties, not a container that needs to be preserved. Reusing the variable name for the next line is safe because the previous line is already committed to the sheet's shape collection.


Managing existing lines

A worksheet that already contains lines — whether added by your code, imported from a file, or drawn by a user — exposes them through the sheet.Shapes collection. Each shape can be retrieved by index and modified through its properties:

// Get the first shape in the worksheet
let shape = sheet.Shapes.get(0);
// Modify its properties — color, dash style, etc.
shape.Color = xlsModule.Color.get_Red();

For deletion, sheet.Shapes.Remove(index) removes the shape at the specified index. To remove lines selectively — by name, by type, or by position — iterate the collection and remove matching shapes. Remove from the last index downward when deleting in a loop, since removing an element shifts the indices of all elements after it.


Common issues

The arrowhead is not showing. BeginArrowHeadStyle or EndArrowHeadStyle was not set, or was set to LineNoArrow. Check which end you expect the arrow on and assign the corresponding property. A line with neither property set has no arrows at either end.

The line appears in the wrong position. Top and Left are in pixels, not rows and columns. A value of Top = 10 places the line 10 pixels from the top of the sheet, not on row 10. If you are used to the Lines.AddLine() API, this is the most common source of misplacement.

The elbow connector bends in the wrong direction. The bend direction depends on the signs and relative magnitudes of Width and Height. A positive Width with a positive Height bends down-right. Swap the sign or exchange the two values to change the bend. Test with small values first.

The curved line does not curve the way I expected. A CurveLine through TypedLines draws a smooth arc between the start and end points, and the arc's shape is influenced by Width and Height. Unlike an elbow connector, which has a single right-angle bend, a curve is continuous — but its exact path depends on the dimensions, so verify the output before relying on it for a precise layout.


FAQ

What is the difference between LineArrow and LineArrowOpen?

LineArrow draws a filled triangular arrowhead. LineArrowOpen draws an open V-shaped arrowhead — two strokes without a fill. The open style is common in data-flow and entity-relationship diagrams where the arrow indicates direction without implying a specific mechanism.

Can I set different arrow styles on the two ends?

Yes. BeginArrowHeadStyle and EndArrowHeadStyle are independent properties. A line with LineArrow on one end and LineArrowOpen on the other is valid and communicates that one direction is definite while the other is tentative.

How do pixel coordinates relate to the worksheet layout?

Pixel coordinates are measured from the top-left corner of the worksheet. Row heights and column widths in Excel are measured in points and characters respectively, so converting between cell positions and pixel coordinates requires accounting for the current row heights and column widths. For lines that need to align with cell boundaries, Lines.AddLine() with row and column parameters may be simpler.

Can I mix Lines.AddLine() and TypedLines.AddLine() in the same worksheet?

Yes. Both APIs add shapes to the same worksheet's shape collection. A worksheet can contain basic line shapes and arrow-tipped lines simultaneously.

Does this require Excel to be installed?

No. The engine runs as WebAssembly in the browser. Lines and arrows are written as standard shape objects in the worksheet XML, and Excel renders them natively when the file is opened.


See Also