Create SmartArt Graphics in PowerPoint with JavaScript in React

When a process, hierarchy, or cycle is written as a list of sentences, readers have to compare line after line to work out the order and the relationships. A SmartArt graphic arranges the nodes according to a layout and draws the connections directly, and it re-flows as nodes are added to it. Drawing the same diagram by hand in PowerPoint is slow and makes consistent spacing and alignment hard to keep.

This article uses Spire.Presentation for JavaScript to create and adjust SmartArt graphics in PowerPoint in the browser. The whole process runs locally on the user's device through WebAssembly, requires no Office installation and no back-end service, and the presentation never leaves the browser.

The article covers two features:

For installation and project configuration, see Integrating Spire.Presentation for JavaScript in a React Project. The examples below assume that Spire.Presentation for JavaScript is installed and the WebAssembly module has been initialized.


Create SmartArt Graphics in PowerPoint

To create SmartArt graphics in PowerPoint, start by choosing a layout that matches the relationship in the content, then write the text into the nodes. The layout decides how the nodes are arranged and where the connectors run; it is specified once at creation, and only the node text needs to be maintained afterwards. Once inserted, the graphic can still be moved and resized like any other shape.

What you write What you get
slide.Shapes.AppendSmartArt(x, y, width, height, layoutType) Adds a SmartArt graphic of the given layout at the specified position and size
smartArt.Nodes.Count The number of nodes currently in the graphic
smartArt.Nodes.RemoveNode({ index: i }) Removes the node at index i
smartArt.Nodes.AddNode() Appends a node to the end of the node collection
node.TextFrame.Text Sets or reads the text of a node

The steps are:

  1. Get the Spire.Presentation WASM module, make sure it is ready, and load the font file and the presentation into the VFS.
  2. Create a Presentation object, call LoadFromFile() to load the presentation, and use Slides.get_Item() to get the slide that will hold the graphic.
  3. Call Shapes.AppendSmartArt() with the position, size, and a SmartArtLayoutType to get the ISmartArt object.
  4. Walk from Nodes.Count downwards and call Nodes.RemoveNode() to remove the placeholder nodes that come with the layout.
  5. Call Nodes.AddNode() in order and write the text through TextFrame.Text.
  6. Call Presentation.SaveToFile() to save the result, release the presentation with Dispose(), then read the file from the VFS and trigger the download.

The code for creating SmartArt graphics in PowerPoint is shown below:

function App() {
  const createSmartArt = async () => {
    // Get the Spire.Presentation WASM module
    const pptModule = window.wasmModule?.spirepresentation;

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

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

    // Load the presentation and get the first slide
    const ppt = new pptModule.Presentation();
    ppt.LoadFromFile(inputFileName);
    const slide = ppt.Slides.get_Item(0);

    // Add a process-layout SmartArt at the specified position and size
    const smartArt = slide.Shapes.AppendSmartArt(50, 160, 620, 200, pptModule.SmartArtLayoutType.BasicProcess);

    // Remove the placeholder nodes that come with the layout
    for (let i = smartArt.Nodes.Count - 1; i >= 0; i--) {
      smartArt.Nodes.RemoveNode({ index: i });
    }

    // Add the nodes in process order and write their text
    const steps = ['Requirements', 'Design', 'Development', 'Launch'];
    for (const text of steps) {
      const node = smartArt.Nodes.AddNode();
      node.TextFrame.Text = text;
    }

    // Save the result file
    const outputFileName = 'CreateSmartArt.pptx';
    ppt.SaveToFile({ file: outputFileName, fileFormat: pptModule.FileFormat.Pptx2013 });
    ppt.Dispose();

    // Read the generated 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.presentationml.presentation' });
    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 SmartArt Graphics</h1>
      <button onClick={createSmartArt}>
        Create SmartArt
      </button>
    </div>
  );
}

export default App;

Presentation after creating a SmartArt graphic in PowerPoint:

Presentation after creating a SmartArt graphic in PowerPoint


Add Nodes to a SmartArt Graphic

When you add nodes to a SmartArt graphic, you can build the hierarchy level by level: add a top-level node first, then add subordinate nodes to its child node collection, or insert one at a given position so the new node lands in the right order. The text and reporting relations of the existing nodes stay as they are, and the graphic re-flows around the new node count.

What you write What you get
smartArt.Nodes.AddNode() Adds a node at the top level of the graphic
node.ChildNodes.AddNode() Appends a child node under the specified node
node.ChildNodes.AddNodeByPosition(position) Inserts a child node at the specified position under the node and shifts the following children back
node.TextFrame.Text Sets the text of the new node

The steps are:

  1. Get the Spire.Presentation WASM module, make sure it is ready, and load the font file and the presentation into the VFS.
  2. Create a Presentation object, call LoadFromFile() to load the presentation, use Slides.get_Item() to get the slide, and add an organization-chart SmartArt with Shapes.AppendSmartArt().
  3. Iterate the node collection backwards and clear the placeholder nodes that come with the layout with Nodes.RemoveNode().
  4. Call Nodes.AddNode() to add the top-level node and write its text with TextFrame.Text.
  5. Add departments under the top-level node with ChildNodes.AddNode(), then insert one at a given position with ChildNodes.AddNodeByPosition().
  6. Call AddNode() on a department's ChildNodes to add the next level.
  7. Call Presentation.SaveToFile() to save the result, release the presentation with Dispose(), then read the file from the VFS and trigger the download.

The code for adding nodes to a SmartArt graphic is shown below:

function App() {
  const addNodes = async () => {
    // Get the Spire.Presentation WASM module
    const pptModule = window.wasmModule?.spirepresentation;

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

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

    // Load the presentation and get the first slide
    const ppt = new pptModule.Presentation();
    ppt.LoadFromFile(inputFileName);
    const slide = ppt.Slides.get_Item(0);

    // Add an organization-chart SmartArt and clear its placeholder nodes
    const smartArt = slide.Shapes.AppendSmartArt(50, 160, 620, 200, pptModule.SmartArtLayoutType.OrganizationChart);
    for (let i = smartArt.Nodes.Count - 1; i >= 0; i--) {
      smartArt.Nodes.RemoveNode({ index: i });
    }

    // Top-level node
    const root = smartArt.Nodes.AddNode();
    root.TextFrame.Text = 'Headquarters';

    // Add departments under the top-level node
    const dev = root.ChildNodes.AddNode();
    dev.TextFrame.Text = 'Engineering';
    const mkt = root.ChildNodes.AddNode();
    mkt.TextFrame.Text = 'Marketing';

    // Insert a department at a given position
    const ops = root.ChildNodes.AddNodeByPosition(1);
    ops.TextFrame.Text = 'Operations';

    // Add a team under the engineering department
    const team = dev.ChildNodes.AddNode();
    team.TextFrame.Text = 'Frontend Team';

    // Save the result file
    const outputFileName = 'AddSmartArtNodes.pptx';
    ppt.SaveToFile({ file: outputFileName, fileFormat: pptModule.FileFormat.Pptx2013 });
    ppt.Dispose();

    // Read the generated 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.presentationml.presentation' });
    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 SmartArt Nodes</h1>
      <button onClick={addNodes}>
        Add Nodes
      </button>
    </div>
  );
}

export default App;

Presentation after adding nodes to the SmartArt graphic:

Presentation after adding nodes to the SmartArt graphic


FAQ

What is the difference between Nodes and ChildNodes

Cause: Nodes returns the nodes at every level of the graphic, while ChildNodes returns only the direct children of one node. The two collections serve different purposes.

Solution: Use Nodes to walk the whole graphic, and a node's ChildNodes to read, add, or remove its direct children:

// Every node in the graphic
for (let i = 0; i < smartArt.Nodes.Count; i++) {
  console.log(smartArt.Nodes.get_Item(i).TextFrame.Text);
}

// The direct children of one node
const root = smartArt.Nodes.get_Item(0);
for (let i = 0; i < root.ChildNodes.Count; i++) {
  console.log(root.ChildNodes.get_Item(i).TextFrame.Text);
}

Why does a node added as a child end up at the top level

Cause: smartArt.Nodes.AddNode() adds a node at the top level of the graphic instead of under the current node. On an organization chart the new node becomes another top-level node and stays at level 0.

Solution: To add a node as a subordinate, call ChildNodes.AddNode() on that node; to insert it at a position, use ChildNodes.AddNodeByPosition():

const root = smartArt.Nodes.get_Item(0);
const child = root.ChildNodes.AddNode();
child.TextFrame.Text = 'New node';

Get a Free License

If you wish to delete the evaluation message from the resulting documents, or to get rid of function limitations, please contact sales to obtain a valid 30-day temporary license.