Create Word Tables with JavaScript in React

Creating tables in Word documents is one of the most common requirements in daily office development — whether for data reports, product catalogs, or statistical analysis, tables present information clearly in a structured format. Spire.Doc for JavaScript runs entirely in the browser via WebAssembly, using a virtual file system (VFS) to manage font and file resources — no backend server required.

This article covers three core features:

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


Create a Formatted Data Table

In real-world development, the most common scenario is writing data returned from a backend into a Word document as a table. The core workflow involves three steps: first, load font files into the WASM virtual file system via FetchFileToVFS; then instantiate a Document to create the document, add a table via AddTable, populate it with data, and configure header rows, alignment, and alternating row colors; finally, save the document, read the generated file from VFS, wrap it as a Blob, and trigger a browser download.

function addTable(section) {
  let docModule = window.wasmModule.spiredoc;
  let header = ["Name", "Capital", "Continent", "Area", "Population"];
  let data =
    [
      ["Argentina", "Buenos Aires", "South America", "2777815", "32300003"],
      ["Bolivia", "La Paz", "South America", "1098575", "7300000"],
      ["Brazil", "Brasilia", "South America", "8511196", "150400000"],
      ["Canada", "Ottawa", "North America", "9976147", "26500000"],
      ["Chile", "Santiago", "South America", "756943", "13200000"],
      ["Colombia", "Bagota", "South America", "1138907", "33000000"],
      ["Cuba", "Havana", "North America", "114524", "10600000"],
      ["Ecuador", "Quito", "South America", "455502", "10600000"],
      ["El Salvador", "San Salvador", "North America", "20865", "5300000"],
      ["Guyana", "Georgetown", "South America", "214969", "800000"],
      ["Jamaica", "Kingston", "North America", "11424", "2500000"],
      ["Mexico", "Mexico City", "North America", "1967180", "88600000"],
      ["Nicaragua", "Managua", "North America", "139000", "3900000"],
      ["Paraguay", "Asuncion", "South America", "406576", "4660000"],
      ["Peru", "Lima", "South America", "1285215", "21600000"],
      ["United States of America", "Washington", "North America", "9363130", "249200000"],
      ["Uruguay", "Montevideo", "South America", "176140", "3002000"],
      ["Venezuela", "Caracas", "South America", "912047", "19700000"]
    ];
  let table = section.AddTable({ showBorder: true });
  table.ResetCells(data.length + 1, header.length);

  // Set up the header row
  let row = table.Rows.get_Item(0);
  row.IsHeader = true;
  row.Height = 20;
  row.HeightType = docModule.TableRowHeightType.Exactly;
  for (let i = 0; i < row.Cells.Count; i++) {
    row.Cells.get_Item(i).CellFormat.Shading.BackgroundPatternColor = docModule.Color.get_Gray();
  }

  for (let i = 0; i < header.length; i++) {
    row.Cells.get_Item(i).CellFormat.VerticalAlignment = docModule.VerticalAlignment.Middle;
    let p = row.Cells.get_Item(i).AddParagraph();
    p.Format.HorizontalAlignment = docModule.HorizontalAlignment.Center;
    let txtRange = p.AppendText(header[i]);
    txtRange.CharacterFormat.Bold = true;
  }

  // Populate data rows with alternating row colors
  for (let r = 0; r < data.length; r++) {
    let dataRow = table.Rows.get_Item(r + 1);
    dataRow.Height = 20;
    dataRow.HeightType = docModule.TableRowHeightType.Exactly;
    for (let i = 0; i < dataRow.Cells.Count; i++) {
      dataRow.Cells.get_Item(i).CellFormat.Shading.BackgroundPatternColor = docModule.Color.Empty();
    }
    for (let c = 0; c < data[r].length; c++) {
      dataRow.Cells.get_Item(c).CellFormat.VerticalAlignment = docModule.VerticalAlignment.Middle;
      dataRow.Cells.get_Item(c).AddParagraph().AppendText(data[r][c]);
    }
  }

  // Apply light blue background to even rows
  for (let j = 1; j < table.Rows.Count; j++) {
    if (j % 2 == 0) {
      let row2 = table.Rows.get_Item(j);
      for (let f = 0; f < row2.Cells.Count; f++) {
        row2.Cells.get_Item(f).CellFormat.Shading.BackgroundPatternColor = docModule.Color.get_LightBlue();
      }
    }
  }
}

function App() {
  const CreateTable = async () => {
    // Get the Spire.Doc WASM module
    const docModule = window.wasmModule?.spiredoc;

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

    // Load font files into VFS
    await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
 
    // Create a blank document
    let doc = new docModule.Document();
    let section = doc.AddSection();

    // Add the table
    addTable(section);

    // Define the output file name
    const outputFileName = "CreateTable_output.docx";

    // Save the document
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });

    // Release resources
    doc.Dispose();

    // Read the generated file from VFS and trigger download
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
    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>Click the button below to create a table in a Word document.</h1>
      <button onClick={CreateTable}>
        Generate
      </button>
    </div>
  );
}

export default App;

Word output generated from a formatted data table

Word output generated from a formatted data table


Create a Table from HTML

In web development, HTML tables are a universal format for displaying data. Spire.Doc provides the AppendHTML method, which can parse an HTML string directly into a Word document table, greatly simplifying the conversion from web content to Word documents. This is particularly useful for scenarios where you need to export table data from a web page to a Word document.

function App() {
  const CreateTableFromHTML = async () => {
    // Get the Spire.Doc WASM module
    const docModule = window.wasmModule?.spiredoc;

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

    // Load font files into VFS
    await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);
 
    // HTML string
    let HTML = "<table border='2px'>" +
      "<tr>" +
      "<td>Row 1, Cell 1</td>" +
      "<td>Row 1, Cell 2</td>" +
      "</tr>" +
      "<tr>" +
      "<td>Row 2, Cell 2</td>" +
      "<td>Row 2, Cell 2</td>" +
      "</tr>" +
      "</table>";

    // Create a Word document
    let doc = new docModule.Document();

    // Add a section
    let section = doc.AddSection();

    // Add a paragraph and append the HTML string
    section.AddParagraph().AppendHTML(HTML);

    // Define the output file name
    const outputFileName = "CreateTableFromHTML_output.docx";

    // Save the document
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });

    // Release resources
    doc.Dispose();

    // Read the generated file from VFS and trigger download
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
    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>Click the button below to create a table from HTML in a Word document.</h1>
      <button onClick={CreateTableFromHTML}>
        Generate
      </button>
    </div>
  );
}

export default App;

Word table created from HTML

Word table created from HTML


Create a Nested Table

A nested table is a table inserted within a cell of another table. This is commonly used for complex document layouts — for example, in a product catalog, the main table displays product names and descriptions, while a sub-table containing specification parameters (number, item, price) is embedded inside the description cell. Spire.Doc makes nested table creation easy with the Cell.AddTable method.

function App() {
  const CreateNestedTable = async () => {
    // Get the Spire.Doc WASM module
    const docModule = window.wasmModule?.spiredoc;

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

   // Load font and document files into VFS
    await window.spire.FetchFileToVFS('ARIALUNI.TTF', '/Library/Fonts/', `${process.env.PUBLIC_URL}/font/`);

    // Create a new document
    let doc = new docModule.Document();
    let section = doc.AddSection();

    // Add main table (2 rows, 2 columns)
    let table = section.AddTable({ showBorder: true });
    table.ResetCells(1, 2);

    // Set column widths
    table.Rows.get_Item(0).Cells.get_Item(0).SetCellWidth(70, docModule.CellWidthType.Point);
    table.Rows.get_Item(0).Cells.get_Item(1).SetCellWidth(150, docModule.CellWidthType.Point);
    table.Rows.get_Item(0).Height=200;
    table.AutoFit(docModule.AutoFitBehaviorType.AutoFitToWindow);

    // Insert content into cells
    table.Rows.get_Item(0).Cells.get_Item(0).AddParagraph().AppendText("Spire.Doc for JavaScript");
    let text = "Spire.Doc for JavaScript is a professional Word " +
      "JavaScript library designed for developers to quickly and " +
      "high-quality create, read, write, convert, and print Word " +
      "document files on any JavaScript platform.";
    table.Rows.get_Item(0).Cells.get_Item(1).AddParagraph().AppendText(text);

    table.Rows.get_Item(0).Cells.get_Item(1).AddParagraph();
    
    // Add a nested table in the cell (first row, second column)
    let nestedTable = table.Rows.get_Item(0).Cells.get_Item(1).AddTable({ showBorder: true });
    nestedTable.ResetCells(5, 2);
    nestedTable.AutoFit(docModule.AutoFitBehaviorType.AutoFitToContents);

    // Fill nested table content
    nestedTable.Rows.get_Item(0).Cells.get_Item(0).AddParagraph().AppendText("Feature Module");
    nestedTable.Rows.get_Item(0).Cells.get_Item(1).AddParagraph().AppendText("Typical Use Cases");

    nestedTable.Rows.get_Item(1).Cells.get_Item(0).AddParagraph().AppendText("Document Generation");
    nestedTable.Rows.get_Item(2).Cells.get_Item(0).AddParagraph().AppendText("Format Conversion");
    nestedTable.Rows.get_Item(3).Cells.get_Item(0).AddParagraph().AppendText("Content Editing");
    nestedTable.Rows.get_Item(4).Cells.get_Item(0).AddParagraph().AppendText("Print Service");

    nestedTable.Rows.get_Item(1).Cells.get_Item(1).AddParagraph().AppendText("Dynamically generate contracts, invoices, data reports, and mail merge");
    nestedTable.Rows.get_Item(2).Cells.get_Item(1).AddParagraph().AppendText("Convert between Word and PDF, HTML, RTF, XML, images, and more");
    nestedTable.Rows.get_Item(3).Cells.get_Item(1).AddParagraph().AppendText("Extract text/images, add watermarks, track revisions, and fill forms");
    nestedTable.Rows.get_Item(4).Cells.get_Item(1).AddParagraph().AppendText("Background silent printing, custom paper size, and page setup");

    // Define the output file name
    const outputFileName = "CreateNestedTable_output-en.docx";

    // Save the document
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2013 });

    // Release resources
    doc.Dispose();

    // Read the generated file from VFS and trigger download
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' });
    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>Click the button below to create a nested table in a Word document.</h1>
      <button onClick={CreateNestedTable}>
        Generate
      </button>
    </div>
  );
}

export default App;

Nested table output in Word

Nested table output in Word


FAQ

The downloaded file cannot be opened or appears corrupted

Cause: The MIME type is incorrect when creating the Blob, so the browser cannot properly identify the file format.

Solution: Use the correct Word document MIME type:

const modifiedFile = new Blob([fileArray], {
  type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
});

Table borders are missing or inconsistent

Cause: When adding a table with AddTable({ showBorder: true }), borders are enabled by default, but tables created directly via the Table constructor need borders set manually.

Solution: When creating a table via the constructor, explicitly set the border type:

let table = new wasmModule.Table(doc, false);
table.Format.Borders.BorderType = wasmModule.BorderStyle.Single;

Get a Free License

If you want to remove the evaluation message from the result document, or eliminate functional limitations, contact our sales team to request a 30-day temporary license.