Convert Markdown to PDF with JavaScript in React

2026-09-11 06:20:41 Written by  alice yang
Rate this item
(0 votes)

Visual Guide on Converting Markdown to PDF with JavaScript

Markdown is convenient for writing documentation, README files, notes, and other structured content. But when the content needs to be printed, archived, or shared in a fixed-layout format, PDF is often more practical.

In a React application, you can convert Markdown to PDF using Spire.Doc for JavaScript. The library runs through WebAssembly (WASM), allowing Markdown content to be processed and PDF files to be generated locally in the browser without sending files to a server.

This tutorial covers three common conversion scenarios:

Set Up Spire.Doc for JavaScript in React

Before converting Markdown files, you need to integrate Spire.Doc for JavaScript into your React project and prepare the required WebAssembly runtime files.

For a detailed setup guide, see How to Integrate Spire.Doc for JavaScript in a React Project.

Step 1: Install the Package

Run the following command in your React project directory to install the required package from npm:

npm i spire.office

Step 2: Add the Required Runtime Files

Copy the following files and folders from node_modules/spire.office to your project's public directory:

_framework
spire.doc.js
Spire.Doc.Wasm.zip
spire.common.js
Spire.Common.Wasm.zip

The examples below also use CALIBRI.ttf for PDF text rendering. Place the font under:

public/static/font/

For file-based conversion, place the sample Markdown file under:

public/static/data/

The relevant project structure should look like this:

public/
├── _framework/
├── spire.doc.js
├── Spire.Doc.Wasm.zip
├── spire.common.js
├── Spire.Common.Wasm.zip
└── static/
    ├── data/
    │   └── MarkdownExample.md
    └── font/
        └── CALIBRI.ttf

Note: The examples use process.env.PUBLIC_URL, which follows the Create React App convention. If your project uses Vite or another build tool, adjust the public asset paths accordingly.

Convert a Markdown File to PDF with JavaScript

Converting a Markdown file to PDF involves 4 main steps:

  1. Load the required font and Markdown file into the WASM virtual file system (VFS).
  2. Call Document.LoadFromFile() with FileFormat.Markdown to load the Markdown file into a Document object.
  3. Call Document.SaveToFile() with FileFormat.PDF to save the loaded document as a PDF file.
  4. Read the generated PDF from the VFS and download it in the browser.

The following JavaScript example loads a .md file and saves it as a .pdf file:

import React, { useEffect, useState } from 'react';

function App() {
  const [wasmModule, setWasmModule] = useState(null);

  // Initialize the Spire.Doc WebAssembly module
  useEffect(() => {
    (async () => {
      try {
        const publicUrl = process.env.PUBLIC_URL || '';

        const spireModule = await import(
          /* webpackIgnore: true */
          `${publicUrl}/spire.doc.js`
        );

        const rawModule = spireModule.default || spireModule;

        window.wasmModule =
          typeof rawModule === 'function'
            ? await rawModule({
                locateFile: (path) =>
                  path.endsWith('.wasm')
                    ? `${publicUrl}/${path}`
                    : path
              })
            : rawModule;

        setWasmModule(window.wasmModule);
      } catch (error) {
        console.error(
          'Failed to load the Spire.Doc WASM module:',
          error
        );
      }
    })();
  }, []);

  // Download a file generated in the WASM virtual file system
  const downloadVfsFile = (fileName, mimeType) => {
    const fileData =
      window.dotnetRuntime.Module.FS.readFile(fileName);

    const blob = new Blob(
      [fileData],
      { type: mimeType }
    );

    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');

    link.href = url;
    link.download = fileName;

    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);

    URL.revokeObjectURL(url);
  };

  const convertMarkdownToPdf = async () => {
    const docModule = window.wasmModule?.spiredoc;

    if (!docModule) return;

    const publicUrl = process.env.PUBLIC_URL || '';

    // Load the font into the VFS
    await window.spire.FetchFileToVFS(
      'CALIBRI.ttf',
      '/Library/Fonts/',
      `${publicUrl}/static/font/`
    );

    const inputFileName = 'MarkdownExample.md';
    const outputFileName = 'MarkdownToPDF.pdf';

    // Load the Markdown file into the VFS
    await window.spire.FetchFileToVFS(
      inputFileName,
      '',
      `${publicUrl}/static/data/`
    );

    const doc = new docModule.Document();

    try {
      // Load the Markdown file
      doc.LoadFromFile({
        fileName: inputFileName,
        fileFormat: docModule.FileFormat.Markdown
      });

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

      // Download the generated PDF
      downloadVfsFile(
        outputFileName,
        'application/pdf'
      );
    } finally {
      doc.Dispose();
    }
  };

  return (
    <div style={{ textAlign: 'center', padding: '40px' }}>
      <h1>Convert Markdown to PDF</h1>

      <button
        onClick={convertMarkdownToPdf}
        disabled={!wasmModule}
      >
        Convert and Download PDF
      </button>
    </div>
  );
}

export default App;

Run the application and wait for the WASM module to finish loading. Then click Convert and Download PDF. The application will load MarkdownExample.md, convert it to MarkdownToPDF.pdf, and download the generated PDF in the browser.

Output

The generated PDF preserves the main Markdown structure, including headings, paragraphs, lists, and tables:

Side-by-side view of input Markdown and output PDF

Convert Markdown to PDF with Custom Page Settings

The default page layout may not suit every document. A Markdown report containing a wide table, for example, may work better in landscape orientation, while printable documentation may require specific page sizes or margins.

After loading the Markdown file, you can access the document section and adjust its PageSetup properties before generating the PDF.

The following example sets the first section to A4 size, landscape orientation, and 50-point margins:

const section = doc.Sections.get_Item(0);

// Set page size
section.PageSetup.PageSize =
  docModule.PageSize.A4();

// Set page orientation
section.PageSetup.Orientation =
  docModule.PageOrientation.Landscape;

// Set page margins
section.PageSetup.Margins.All = 50;

To apply these settings during Markdown-to-PDF conversion, use the following function:

const convertMarkdownToPdfWithPageSettings = async () => {
  const docModule = window.wasmModule?.spiredoc;

  if (!docModule) return;

  const publicUrl = process.env.PUBLIC_URL || '';

  // Load the font into the VFS
  await window.spire.FetchFileToVFS(
    'CALIBRI.ttf',
    '/Library/Fonts/',
    `${publicUrl}/static/font/`
  );

  const inputFileName = 'MarkdownExample.md';
  const outputFileName =
    'MarkdownToPDFWithPageSettings.pdf';

  // Load the Markdown file into the VFS
  await window.spire.FetchFileToVFS(
    inputFileName,
    '',
    `${publicUrl}/static/data/`
  );

  const doc = new docModule.Document();

  try {
    // Load the Markdown file
    doc.LoadFromFile({
      fileName: inputFileName,
      fileFormat: docModule.FileFormat.Markdown
    });

    // Get the first section
    const section = doc.Sections.get_Item(0);

    // Set page size
    section.PageSetup.PageSize =
      docModule.PageSize.A4();

    // Set landscape orientation
    section.PageSetup.Orientation =
      docModule.PageOrientation.Landscape;

    // Set all margins to 50 points
    section.PageSetup.Margins.All = 50;

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

    // Download the generated PDF
    downloadVfsFile(
      outputFileName,
      'application/pdf'
    );
  } finally {
    doc.Dispose();
  }
};

You can adjust the page size, orientation, and margins according to the content of your Markdown document.

Convert a Markdown String to PDF with JavaScript

Markdown does not always come from a physical .md file. In a React application, the content may already exist as a string from a Markdown editor, textarea, CMS, API response, or application state.

In this case, write the Markdown string to the WASM virtual file system using FS.writeFile(), then load the virtual .md file and convert it to PDF.

const convertMarkdownStringToPdf = async () => {
  const docModule = window.wasmModule?.spiredoc;

  if (!docModule) return;

  const publicUrl = process.env.PUBLIC_URL || '';

  // Load the font into the VFS
  await window.spire.FetchFileToVFS(
    'CALIBRI.ttf',
    '/Library/Fonts/',
    `${publicUrl}/static/font/`
  );

  const markdownString = `# Project Notes

This PDF was generated from **Markdown stored in a React string**.

## Tasks

- Review the draft
- Export the final copy
- Share the PDF

## Task Status

| Item | Status |
| --- | --- |
| Draft | Done |
| Review | Pending |
`;

  const inputFileName = 'MarkdownInput.md';
  const outputFileName = 'MarkdownStringToPDF.pdf';

  // Write the Markdown string to the VFS
  window.dotnetRuntime.Module.FS.writeFile(
    inputFileName,
    markdownString,
    { encoding: 'utf8' }
  );

  const doc = new docModule.Document();

  try {
    // Load the virtual Markdown file
    doc.LoadFromFile({
      fileName: inputFileName,
      fileFormat: docModule.FileFormat.Markdown
    });

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

    // Download the generated PDF
    downloadVfsFile(
      outputFileName,
      'application/pdf'
    );
  } finally {
    doc.Dispose();
  }
};

In an actual application, replace the sample string with the Markdown content from your existing data source:

const markdownString = editorValue;

or:

const markdownString = apiResponse.content;

The rest of the PDF conversion workflow remains the same.

Output

PDF generated from the Markdown String

Why Are Fonts Loaded into the VFS?

PDF generation requires font data to render text correctly. In the examples above, CALIBRI.ttf is loaded into the WASM virtual file system before the Markdown document is processed:

await window.spire.FetchFileToVFS(
  'CALIBRI.ttf',
  '/Library/Fonts/',
  `${publicUrl}/static/font/`
);

If the Markdown contains characters that are not supported by the selected font, load an appropriate font into /Library/Fonts/ as well.

This is particularly important when generating PDFs containing Chinese, Japanese, Korean, Arabic, or other multilingual text.

FAQs

Can I Convert a User-Uploaded Markdown File to PDF?

Yes. Instead of loading a fixed .md file from the public directory, you can read the uploaded Markdown file in the browser, write its content to the WASM virtual file system, and then load it with FileFormat.Markdown. This allows users to select and convert their own Markdown files directly in a React application.

Why Are Some Characters Missing from the Generated PDF?

This usually happens when the font required to display those characters is not available in the WASM environment. Load a font that supports the characters used in your Markdown into /Library/Fonts/ before generating the PDF. This is especially important for multilingual content.

What Should I Do If a Wide Markdown Table Is Cut Off?

Try switching the page to landscape orientation, reducing the margins, or using a larger page size before saving the document as PDF.

Why Are Images in My Markdown Missing from the PDF?

Markdown usually references images through a file path or URL rather than embedding the image data directly. Make sure the image files referenced in the Markdown are available during conversion and that their paths can be resolved by the conversion environment. Relative image paths may require additional handling depending on where the Markdown and image files are stored.

Does the Markdown-to-PDF Conversion Run Locally in the Browser?

Yes. In this React implementation, Spire.Doc for JavaScript runs through WebAssembly, while the Markdown input and generated PDF are processed through the browser-side virtual file system. A backend is not required for the conversion itself, although your application may still use one for file storage, authentication, or other server-side operations.

Conclusion

This article demonstrated how to convert Markdown to PDF with JavaScript in a React application, including basic file conversion, custom page settings, and conversion from Markdown strings.

With Spire.Doc for JavaScript, developers can load Markdown content, control PDF page layout, and generate PDF files directly in the browser through WebAssembly. This approach can be used for documentation tools, Markdown editors, reporting systems, and other applications that need to export Markdown content as PDF.

Get a Free License

To fully experience the capabilities of Spire.Doc for JavaScript without any evaluation limitations, you can request a free 30-day trial license.