Technical documentation, API references and release notes are increasingly maintained in Markdown: it is easy to keep in a code repository, easy to review, and easy to compare between versions. For external delivery, however, the recipient usually needs a Word or PDF document. Copying and pasting into a desktop application loses the formatting, and tables and code blocks have to be rearranged by hand; converting on a server takes the source file off the user's device.

This article converts Markdown to Word documents and PDF documents in the browser with Spire.Doc for JavaScript. The library runs in the browser as a WebAssembly module, the source file is read through a virtual file system (VFS), and the conversion result is written back to the VFS before the download is triggered. The whole process requires neither an Office installation nor any backend service.

This article covers three features:

For installation and project setup, refer to Integrating Spire.Doc for JavaScript in a React Project. The examples below assume that Spire.Doc is installed and the WebAssembly module is initialized. The sample Markdown source and the template document are placed in the public/data/ directory, and the font files in the public/static/font/ directory. To make them easy to run directly, the code for each feature is a complete single file, so the content of App.js can be replaced with it wholesale.


Convert a Markdown Document to Word

Spire.Doc for JavaScript loads the source file with Document.LoadFromFile(), and the second parameter specifies the file format. Pass FileFormat.Markdown when loading Markdown: the library parses headings, paragraphs, lists, tables, quotes, code blocks and images according to Markdown syntax rules, and turns them into the corresponding Word document objects.

The syntax used in the source file and the styles applied after conversion correspond as follows:

Markdown syntax Style applied after conversion Notes
# to ###### Heading 1 to Heading 6 The six heading levels map to the six built-in heading styles respectively
Ordinary paragraphs Normal Paragraph text and inline formatting such as bold and italic are kept
> quotes Quote Converted to an indented quote paragraph
- lists, 1. lists List paragraphs Bulleted and numbered lists become automatically numbered items
Pipe tables Word tables The first row becomes the header, and cells carry thin borders
Backtick inline code InlineCode A character-level style that affects only the marked text
Fenced code blocks FencedCode plus the language name A code block marked js, for example, is given FencedCodejs
Indented code blocks FencedCode Code blocks without a language label

The specific steps are as follows:

  1. Get the Spire.Doc WASM module and confirm that it is ready.
  2. Load the Markdown source file into the virtual file system (VFS).
  3. Create a Document instance and load the source file with LoadFromFile() as FileFormat.Markdown.
  4. Save the document with SaveToFile() as a DOCX file.
  5. Read the result file from the VFS and trigger its browser download.

The code for converting a Markdown document to a Word document is as follows:

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

    // Make sure the WASM module has fully loaded
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

    // Load the Markdown source and the images it references into VFS
    await window.spire.FetchFileToVFS('Sample.md', "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS('pipeline.png', "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS('msyh.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);
    await window.spire.FetchFileToVFS('msyhbd.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);

    // Create a Document instance and load the source file as Markdown
    const doc = new docModule.Document();
    doc.LoadFromFile('Sample.md', docModule.FileFormat.Markdown);

    // Save as a Word document
    const outputFileName = 'MarkdownToWord.docx';
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2016 });
    doc.Dispose();

    // Read the generated file from VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { 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>Convert Markdown to Word</h1>
      <button onClick={convertToWord}>
        Convert to Word
      </button>
    </div>
  );
}

export default App;

The converted Word document is shown below; the headings, lists, quotes, tables and code blocks have all been restored according to the structure of the source file:

Word document converted with the default styles

Word document converted with the default styles


Convert a Markdown Document to PDF

Once Markdown has been loaded, the result is a complete Word document object, so the same object can be saved as DOCX or exported directly to PDF without reading the source file again. For export, simply change the fileFormat of SaveToFile() to FileFormat.PDF. The page size and margins follow the section settings of the document, and the pagination is determined by the layout computed during export.

Unlike DOCX, PDF requires the text to be genuinely rasterized, so before export the fonts used by the document should be loaded into the font directory of the virtual file system; the examples place the fonts in /Library/Fonts/.

The specific steps are as follows:

  1. Get the Spire.Doc WASM module and confirm that it is ready.
  2. Load the Markdown source file and the font files into the virtual file system (VFS).
  3. Create a Document instance and load the source file with LoadFromFile() as FileFormat.Markdown.
  4. Export the document with SaveToFile() as a PDF file.
  5. Read the result file from the VFS and trigger its browser download.

The code for converting a Markdown document to a PDF document is as follows:

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

    // Make sure the WASM module has fully loaded
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

    // Load the Markdown source and the fonts into VFS
    await window.spire.FetchFileToVFS('Sample.md', "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS('pipeline.png', "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS('msyh.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);
    await window.spire.FetchFileToVFS('msyhbd.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);

    // Create a Document instance and load the source file as Markdown
    const doc = new docModule.Document();
    doc.LoadFromFile('Sample.md', docModule.FileFormat.Markdown);

    // Export as a PDF document
    const outputFileName = 'MarkdownToPdf.pdf';
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.PDF });
    doc.Dispose();

    // Read the generated file from VFS and trigger the 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 Markdown to PDF</h1>
      <button onClick={convertToPdf}>
        Convert to PDF
      </button>
    </div>
  );
}

export default App;

The PDF document exported from the same Markdown is shown below:

PDF document exported from the same Markdown

PDF document exported from the same Markdown


Use Template Styles to Convert Markdown to Word

The document produced by the default rules uses the built-in styles, whose fonts, color schemes and line spacing are generic in appearance. In actual delivery, a document often has to meet the layout requirements of a company or department: which font size the headings use, which line spacing the body text uses, whether a separator line appears below a heading. These requirements have usually already been organized into a Word template; all that is needed is to copy the styles of the template onto the conversion result.

The current JavaScript version does not provide a method that copies all template styles at once, so the example handles it as follows: first find the style of the same name in the target document, then copy the character formatting and paragraph formatting of the template style onto it item by item. The style names in the template therefore have to match the names of the styles produced by the conversion; the common correspondences are as follows:

Template style name Affected content Settings in the sample template
Normal Body paragraphs Microsoft YaHei 10.5 pt, grey text, 1.35 line spacing
Heading 1 # level-one headings 18 pt bold, dark blue, separator line below
Heading 2 ## level-two headings 14 pt bold, dark green
Heading 3 ### level-three headings 12 pt bold, dark blue
Quote > quote paragraphs 10 pt italic, dark green, left indent

The specific steps are as follows:

  1. Get the Spire.Doc WASM module and confirm that it is ready.
  2. Load the Markdown source file and the template document into the virtual file system (VFS).
  3. Create a Document instance and load the source file with LoadFromFile() as FileFormat.Markdown.
  4. Create another Document instance and load the template document, then take its styles by name.
  5. Use the copyStyle() helper to copy the character formatting and paragraph formatting of each template style onto the style of the same name in the target document.
  6. Save the result file with SaveToFile(), then read it from the VFS and trigger the download.

The code for converting Markdown with the template styles is as follows:

// Names of the styles to copy from the template; they must match the styles applied by the Markdown conversion
const TEMPLATE_STYLES = ['Normal', 'Heading 1', 'Heading 2', 'Heading 3', 'Quote'];

// Copy one style from the template document to the style of the same name in the target document
function copyStyle(src, dst) {
  // Character formatting: font, font size, bold, italic, text color
  const sf = src.CharacterFormat;
  const df = dst.CharacterFormat;
  df.FontName = sf.FontName;
  df.FontSize = sf.FontSize;
  df.Bold = sf.Bold;
  df.Italic = sf.Italic;
  df.TextColor = sf.TextColor;

  // Paragraph formatting: spacing before and after, line spacing, indent, alignment and pagination control
  const sp = src.ParagraphFormat;
  const dp = dst.ParagraphFormat;
  dp.BeforeSpacing = sp.BeforeSpacing;
  dp.AfterSpacing = sp.AfterSpacing;
  dp.LineSpacing = sp.LineSpacing;
  dp.LineSpacingRule = sp.LineSpacingRule;
  dp.LeftIndent = sp.LeftIndent;
  dp.FirstLineIndent = sp.FirstLineIndent;
  dp.HorizontalAlignment = sp.HorizontalAlignment;
  dp.KeepFollow = sp.KeepFollow;

  // Paragraph borders: the separator line below a heading
  const sb = sp.Borders.Bottom;
  const db = dp.Borders.Bottom;
  db.BorderType = sb.BorderType;
  db.LineWidth = sb.LineWidth;
  db.Color = sb.Color;
  db.Space = sb.Space;
}

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

    // Make sure the WASM module has fully loaded
    if (!docModule) {
      alert('Spire.Doc is not ready yet');
      return;
    }

    // Load the Markdown source and the template document into VFS
    await window.spire.FetchFileToVFS('Sample.md', "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS('Template.docx', "", `${process.env.PUBLIC_URL}/data/`);
    await window.spire.FetchFileToVFS('msyh.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);
    await window.spire.FetchFileToVFS('msyhbd.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);

    // Load the source file as Markdown
    const doc = new docModule.Document();
    doc.LoadFromFile('Sample.md', docModule.FileFormat.Markdown);

    // Load the template document and take only its styles
    const template = new docModule.Document();
    template.LoadFromFile('Template.docx');

    // Copy each template style onto the style of the same name in the target document
    TEMPLATE_STYLES.forEach((name) => {
      const src = template.Styles.FindByName(name);
      const dst = doc.Styles.FindByName(name);
      if (src && dst) {
        copyStyle(src, dst);
      }
    });
    template.Dispose();

    // Save as a Word document
    const outputFileName = 'MarkdownToWordWithTemplate.docx';
    doc.SaveToFile({ fileName: outputFileName, fileFormat: docModule.FileFormat.Docx2016 });
    doc.Dispose();

    // Read the generated file from VFS and trigger the download
    const fileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const blob = new Blob([fileArray], { 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>Convert Markdown with Template Styles</h1>
      <button onClick={convertWithTemplate}>
        Convert and Apply Template Styles
      </button>
    </div>
  );
}

export default App;

The first page of the Word document after the template styles are applied is shown below; the headings, body text, quotes and tables all follow the fonts, color scheme and line spacing of the template:

First page of the Word document after applying the template styles

First page of the Word document after applying the template styles


The Sample Markdown File

All three features share the same Sample.md, which is placed in the public/data/ directory. The sample is a product release note covering level-one to level-three headings, bulleted lists, quotes, pipe tables, fenced code blocks, inline code, images, and bold and italic text, so that the conversion result of each syntax in Word can be observed side by side.

Images are referenced by relative path; before conversion, the image files have to be loaded into the virtual file system under the same path as written in the Markdown.

The content of the sample Markdown file is as follows:

# Northstar Platform Release Notes

## Overview

Northstar 2026.4 focuses on **document processing inside the browser**. This release moves template rendering, format conversion and batch output into a single WebAssembly pipeline, so that no source file leaves the user's device.

The release has three goals:

- Reduce the time to generate one document from 6 minutes to under 10 seconds.
- Remove the server from the conversion path for contract and payroll files.
- Keep the output page count identical to the on-screen preview.

## What's New

### Browser-side conversion

All conversion work now runs in the browser through a WebAssembly module. Fonts and templates are loaded on demand through a virtual file system, and the result is written back to the same file system before download.

> Files are processed locally. The platform never stores source documents on the server.

### Supported input formats

| Format | Read | Write | Notes |
|---|---|---|---|
| Markdown | Yes | Yes | Headings, lists, tables, images |
| Word (.docx) | Yes | Yes | Styles and fields preserved |
| HTML | Yes | No | External CSS is ignored |
| PDF | Yes | Yes | Page setup follows the section |

### Markdown pipeline

The Markdown loader maps the source structure onto Word building blocks, and the result is exported from the same document object:

![Markdown to Word pipeline](pipeline.png)

- Headings map onto the built-in Heading 1 to Heading 6 styles.
- Bullet and numbered lists keep their nesting level.
- Pipe tables become Word tables with a header row.

```js
const doc = new Document();
doc.LoadFromFile('Sample.md', FileFormat.Markdown);
doc.SaveToFile('Result.docx', FileFormat.Docx2016);
```

## Upgrade Notes

*Existing styles are kept* when a document is loaded, and two behaviours changed in this release:

- Markdown headings now use the built-in Heading styles instead of direct formatting.
- Table borders default to a hairline, single, light grey line.

## Timeline

| Milestone | Date | Status |
|---|---|---|
| Design review | 2026-02-12 | Done |
| Core development | 2026-03-01 | Done |
| Integration testing | 2026-07-20 | In progress |
| Acceptance | 2026-10-15 | Planned |

The template document Template.docx only provides styles; its body content does not take part in the conversion. The style names in the template have to match the names of the styles produced by the conversion (Normal, Heading 1, Heading 2, Heading 3, Quote); styles whose names do not match are not copied.


FAQ

Why is the first paragraph of the converted document a red line of English text

Cause: This line is an evaluation notice inserted by Spire.Doc for JavaScript when the file is saved. Its content is Evaluation Warning: The document was created with Spire.Doc for JavaScript., and it has nothing to do with the content of the source file.

Solution: The notice exists only in the evaluation version; once a license is applied, the saved file no longer contains this paragraph.

Why do the converted headings and body text not use the font and line spacing I expect

Cause: LoadFromFile() converts Markdown with the built-in styles — headings use Heading 1 to Heading 6 and body text uses Normal — and these styles themselves do not define the fonts and color schemes commonly used in corporate documents.

Solution: Organize the layout requirements into a Word template and copy the styles as described in Use Template Styles to Convert Markdown to Word; alternatively, after loading, modify the CharacterFormat and ParagraphFormat of the corresponding styles in doc.Styles directly.

Why do the entries after the first one in a multi-item ordered list end up merged into the first paragraph

Cause: The parser recognizes ordered lists by paragraph; when there is no blank line between items, the text of the second item onwards is treated as a continuation line of the first, and the number is kept in the paragraph as plain text.

Solution: Leave a blank line between items so that each one becomes an independently numbered list item; bulleted lists are not subject to this restriction and can be written consecutively:

1. First step.

2. Second step.

3. Third step.

Why are the images in the Markdown not displayed, or displayed exceptionally large

Cause: Images are read from the virtual file system by the path written in the Markdown; when the file has not been loaded into the VFS it cannot be embedded. Image size is converted from the original pixel dimensions at 96 dpi, so an image with a large pixel width may exceed the text width on an A4 page.

Solution: Load the image into the VFS first, under the same path as written in the Markdown:

await window.spire.FetchFileToVFS('pipeline.png', "", `${process.env.PUBLIC_URL}/data/`);

To specify a width, write the image as an HTML img tag; the width attribute is written into the document in pixels:

<img src="pipeline.png" width="360">

What should I do when the Chinese font in the exported PDF is wrong, or appears blank or as boxes

Cause: A DOCX records only font names, which Word resolves when the file is opened; PDF requires the text to be rendered as graphics, so when the font file has not been loaded, the export can only use a substitute font or leave the text blank.

Solution: Before exporting to PDF, load the fonts used by the document into the font directory of the virtual file system; the examples place them in /Library/Fonts/. When there are many Chinese fonts, it is advisable to load both the regular and the bold face:

await window.spire.FetchFileToVFS('msyh.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);
await window.spire.FetchFileToVFS('msyhbd.ttc', "/Library/Fonts/", `${process.env.PUBLIC_URL}/static/font/`);

Get a Free License

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

When data is split into categories and subcategories, each carrying a value, rows of a table make it hard to see at a glance how much of the whole each category represents. A treemap nests rectangles by hierarchy and sizes each rectangle by its value, so subcategories of the same category sit side by side and their proportions can be compared directly. Turning such data into a treemap, then adding labels and fill colors, produces a chart that can go straight into a report or a shared document. Spire.XLS for JavaScript creates and renders treemap charts in the browser through WebAssembly, with input and output files managed by a virtual file system (VFS) and no backend service required.

This article covers two features:

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


Create a Treemap Chart

A treemap uses rectangle area to represent values and the nesting of rectangles to represent hierarchy. To build a usable chart, start with three columns, category, item, and value, then set the chart type to tree map and fix the chart position and title. Once the chart is created, saving it in an Excel workbook lets the chart be opened, edited, or shared in spreadsheet software.

How to create a treemap chart and what it produces:

Call Result
window.spire.FetchFileToVFS Loads the font file and the test data file into the VFS
workbook.LoadFromFile({ fileName }) Loads the workbook that holds the two-level data
workbook.Worksheets.get(0) Gets the first worksheet of the workbook
sheet.Charts.Add() Adds a chart object to the worksheet
chart.ChartType = xlsModule.ExcelChartType.TreeMap Sets the chart type to tree map
chart.DataRange = sheet.Range.get("A2:C11") Uses two hierarchy columns and one value column as the chart data
chart.ChartTitle Sets the chart title
chart.TopRow / chart.BottomRow / chart.LeftColumn / chart.RightColumn Sets the position and size of the chart on the worksheet
workbook.SaveToFile({ fileName }) Writes the workbook with the treemap chart into the VFS

The steps are:

  1. Load the font file and the Excel test file into the VFS with window.spire.FetchFileToVFS.
  2. Create a workbook with new Workbook() and load the test file with workbook.LoadFromFile.
  3. Get the first worksheet with workbook.Worksheets.get(0).
  4. Add a chart with sheet.Charts.Add() and set chart.ChartType to xlsModule.ExcelChartType.TreeMap.
  5. Set chart.DataRange to sheet.Range.get("A2:C11"), where the first two columns are the group and the item and the third column decides the rectangle area.
  6. Set chart.ChartTitle, then fix the chart position and size through chart.TopRow, chart.BottomRow, chart.LeftColumn, and chart.RightColumn.
  7. Call workbook.SaveToFile to write CreateTreeMap.xlsx, release the workbook with workbook.Dispose, and read the workbook back from the VFS to trigger the download.

Below is the complete example that creates a treemap chart and saves it in an Excel workbook in React:

function App() {
  const createTreeMap = 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 = 'TreeMapData.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}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 chart and set its type to tree map
    const chart = sheet.Charts.Add();
    chart.ChartType = xlsModule.ExcelChartType.TreeMap;

    // Set the data range: the first two columns are the group and the item, the third is the value
    chart.DataRange = sheet.Range.get('A2:C11');

    // Set the position and size of the chart
    chart.TopRow = 1;
    chart.BottomRow = 20;
    chart.LeftColumn = 1;
    chart.RightColumn = 12;

    // Set the chart title
    chart.ChartTitle = 'Area by cities';

    // Save the workbook with the tree map chart into the VFS
    const outputFileName = 'CreateTreeMap.xlsx';
    workbook.SaveToFile({ fileName: outputFileName });

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

    // Read the result back out of 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>Create a Tree Map Chart in React</h1>
      <button id="create-treemap" onClick={createTreeMap}>Create Tree Map</button>
    </div>
  );
}

export default App;

The workbook after creating the treemap chart:

The workbook after creating the treemap chart


Set Treemap Labels and Fill Colors

By default, a treemap is rendered without any data labels, so readers can rely only on the legend to tell the groups apart and cannot see which item each area stands for. Rectangles in the same group also share one color, which makes neighboring areas less distinct. Turning on name labels for the rectangles and then assigning darker fill colors in data point order places each item name directly on its area; the white labels stay legible on the dark fills, and both the group structure and the relative sizes become easy to read.

How to set treemap labels and fill colors and what it produces:

Call Result
chart.Series.get(0).DataPoints Gets the data point collection, one point per rectangle
points.get(i).DataFormat.Fill.FillType = xlsModule.ShapeFillType.SolidColor Makes that rectangle use a solid fill
points.get(i).DataFormat.Fill.ForeColor = colors[i % colors.length] Assigns a fill color to that rectangle
chart.Series.get(0).DataPoints.DefaultDataPoint.DataLabels.HasCategoryName = true Enables category name labels, so item names appear on the rectangles
chart.Series.get(0).DataFormat.TreeMapLabelOption = xlsModule.ExcelTreeMapLabelOption.Overlapping Overlays item names directly on the rectangles and leaves group names in the group corner
xlsModule.ExcelTreeMapLabelOption.Banner Gives group names a strip at the top of each group and keeps item names inside the rectangles
xlsModule.ExcelTreeMapLabelOption.None Hides every label in the chart

The steps are:

  1. Load the test workbook and create the chart as described in the previous section, keeping the data range, position, and title unchanged.
  2. Get the data points with chart.Series.get(0).DataPoints, loop over the data rows, and set DataFormat.Fill.FillType to xlsModule.ShapeFillType.SolidColor and ForeColor to the chosen color for each point.
  3. Set chart.Series.get(0).DataPoints.DefaultDataPoint.DataLabels.HasCategoryName to true. Data labels are off by default on a treemap, so category names appear on the rectangles only after this is enabled.
  4. Set chart.Series.get(0).DataFormat.TreeMapLabelOption to xlsModule.ExcelTreeMapLabelOption.Overlapping so item names are drawn directly on the rectangles; use Banner instead when group names should take a strip at the top of each group.
  5. Write TreeMapStyled.xlsx with workbook.SaveToFile and trigger the download, then release the workbook with workbook.Dispose.

Below is the complete example. The chart setup is kept from the previous section so that it runs on its own; the additions are the fill colors and the labels:

function App() {
  const styleTreeMap = 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 = 'TreeMapData.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}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 tree map chart and set its data range
    const chart = sheet.Charts.Add();
    chart.ChartType = xlsModule.ExcelChartType.TreeMap;
    chart.DataRange = sheet.Range.get('A2:C11');
    chart.TopRow = 1;
    chart.BottomRow = 20;
    chart.LeftColumn = 1;
    chart.RightColumn = 12;
    chart.ChartTitle = 'Area by cities';

    // Prepare the fill colors used in the loop
    const colors = [
      xlsModule.Color.get_DarkGreen(),
      xlsModule.Color.get_DarkBlue(),
      xlsModule.Color.get_DarkGoldenrod(),
      xlsModule.Color.get_DarkRed(),
      xlsModule.Color.get_DarkSlateGray(),
    ];

    // Set the fill color of every rectangle in data point order (10 data rows)
    const points = chart.Series.get(0).DataPoints;
    for (let i = 0; i < 10; i++) {
      points.get(i).DataFormat.Fill.FillType = xlsModule.ShapeFillType.SolidColor;
      points.get(i).DataFormat.Fill.ForeColor = colors[i % colors.length];
    }

    // Enable category name labels and overlay the item names on the rectangles
    chart.Series.get(0).DataPoints.DefaultDataPoint.DataLabels.HasCategoryName = true;
    chart.Series.get(0).DataFormat.TreeMapLabelOption = xlsModule.ExcelTreeMapLabelOption.Overlapping;

    // Save the workbook with the tree map chart into the VFS
    const outputFileName = 'TreeMapStyled.xlsx';
    workbook.SaveToFile({ fileName: outputFileName });

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

    // Read the result back out of 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>Create a Tree Map Chart in React</h1>
      <button id="style-treemap" onClick={styleTreeMap}>Set Labels and Fill Colors</button>
    </div>
  );
}

export default App;

The workbook after setting treemap labels and fill colors:

The workbook after setting treemap labels and fill colors


FAQ

Treemap labels do not appear

Cause: Data labels are off by default on a treemap, so no names are drawn on the rectangles. TreeMapLabelOption only controls how labels are laid out, and setting it alone does not make labels visible.

Solution: Set DataLabels.HasCategoryName on the data points to true first, then set TreeMapLabelOption: use Overlapping to draw item names directly on the rectangles, or Banner to give group names a strip at the top of each group. For example:

chart.Series.get(0).DataPoints.DefaultDataPoint.DataLabels.HasCategoryName = true;
chart.Series.get(0).DataFormat.TreeMapLabelOption = xlsModule.ExcelTreeMapLabelOption.Overlapping;

How can the position and size of a treemap be adjusted

Cause: The position of a chart is controlled by TopRow, BottomRow, LeftColumn, and RightColumn, which mark the first and last row and column the chart covers.

Solution: Adjust these four properties before saving the workbook. Larger values widen the range of rows and columns the chart covers, so the chart takes up more space on the worksheet.

How should the data for a treemap be arranged

Cause: A treemap reads hierarchy and values by column, so the order of the columns determines how groups, items, and areas correspond to one another.

Solution: Arrange the data in three columns: the first for the category, the second for the item, and the third for the value, and keep the value column numeric. Start chart.DataRange at the first data row, for example sheet.Range.get("A2:C11"), so the header row is not included.


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.

Spire.OfficeJS is an online Office document editing suite that supports private deployment. It is also an embeddable online Office editor for developers and enterprises that need to integrate document editing into their own web applications. Users can open, view, edit, and save Word, Excel, and PowerPoint documents directly in the browser, and preview PDFs in read-only mode. No Microsoft Office, WPS, or browser plug-in is required on the client.

Rather than fragmented, low-level APIs, Spire.OfficeJS provides a JavaScript Office editor that can be embedded directly into business pages. The page loads SpireCloudEditor.js, prepares a container element, and passes in the configuration; the editor then loads the corresponding interface as an iframe. Document parsing, layout, rendering, and editing are handled by default by the in-browser WebAssembly document engine. This does not mean there is nothing to deploy, however: SpireCloudEditor.js, the editor UI, the WebAssembly engine, and resources such as fonts must still be hosted on a resource service that the browser can reach. For the full product composition and runtime architecture, see Product Composition and Runtime Architecture.

Key Features

  • Online editing: Online editing for Word, Excel, and PowerPoint documents; open, view, edit, and save documents in the browser, with "Download as" export.
  • PDF preview: Read-only PDF preview within the same interface.
  • Collaboration and review: Supports collaborative editing, comments, revisions, and document history.
  • UI customization: Supports appearance options such as the menu bar, toolbar, interface language, and multiple layouts, for flexible control over the interface.

Product Composition

Spire.OfficeJS ships three editor modules plus PDF preview, all sharing a single editor entry point and runtime:

Document Type Editor Module Document Engine Key Capabilities
Word documents web/editors/spiredocument Spire.Doc WebAssembly Open, view, edit, save, and "Download as"
Excel workbooks web/editors/spirespreadsheet Spire.Xls WebAssembly Open, view, edit, save, and "Download as"
PowerPoint presentations web/editors/spirepresentation Spire.Presentation WebAssembly Open, view, edit, save, and "Download as"
PDF documents — (provided by spiredocument) Spire.Pdf WebAssembly Read-only preview

Each editor module offers three interface layouts: desktop, mobile, and embed. For the complete list of supported formats, see Supported File Formats.

Typical Use Cases

Scenario Typical Requirement Role of Spire.OfficeJS
Document management systems Online preview, editing, and saving of Office files Open the editor directly beside the file list, cutting out uploads and downloads
OA, approval, and contract systems Annotations, revisions, permission control, and audit trails Control edit, comment, and download permissions by role; support review and history
Enterprise cloud storage and SaaS platforms Embed document capabilities into your own product Fit into existing branding and workflows through configuration and UI customization
Online education and training Assignment grading, courseware preview, and group discussion Online editing and comments, with read-only mode for presenting materials
Archives and knowledge bases Unified preview across multiple formats Open Word, Excel, PowerPoint, and PDF documents in a single interface

How It Differs from Self-Built and Public Cloud Solutions

Integrating document capabilities into a business system involves trade-offs whichever approach you take. First, the download–edit–re-upload workflow is fragmented. Second, building browser-side rendering and editing in-house is costly. Third, relying on server-side conversion adds load. And fourth, public cloud office suites make it difficult to fully align the interface, permissions, and data storage with your business system. Spire.OfficeJS handles document processing inside the browser, covers Word, Excel, PowerPoint, and PDF through a single entry point, and keeps both deployment resources and document data on your side through private deployment—making it well suited to scenarios with requirements around data location, UI branding, and deployment method.

Licensing

Spire.OfficeJS is a commercial component. The license file path is specified through a configuration file in the product package. For details on placing and activating the license, see Spire.OfficeJS License Configuration.

Page 2 of 371
page 2