HelpBot Assistant

How can I help you?

Saving PDF Files in the React PDF Viewer

10 Mar 202617 minutes to read

After editing a PDF with annotation tools, you can save the updated file to a server, a database, or download it locally. The following sections show common approaches.

Save and Download the Edited PDF

After editing the PDF document, follow this short, linear flow to persist and retrieve the updated file:

  1. Persist the edited document to your back end (server or database). See “Save modified PDF to server” and “Save modified PDF to a database” below for server-side examples.
  2. Provide the updated file to the user. For a simple download use the built-in toolbar or call the viewer API download().
  3. If you need the edited PDF for custom uploads or processing, use the viewer saveAsBlob() API to obtain a Blob (or convert it to Base64).

This is a summary; use the detailed subsections below for full code samples and server-side instructions.

Save modified PDF to server

To save the modified PDF back to a server, follow these steps.

Step 1: Create a simple PDF Viewer sample in React

Follow the getting-started guide to create a basic PDF Viewer implementation.

Step 2: Modify the PdfViewerController.cs in the web service project

  1. Create a web service project targeting .NET Core 3.0 or later. See this KB Link for details.

  2. Open the PdfViewerController.cs file in your web service project.

  3. Modify the Download() method so it returns the modified document for the viewer to download or store.

public IActionResult Download([FromBody] Dictionary<string, string> jsonObject)
{
  //Initialize the PDF Viewer object with memory cache object
  PdfRenderer pdfviewer = new PdfRenderer(_cache);
  string documentBase = pdfviewer.GetDocumentAsBase64(jsonObject);
  MemoryStream stream = new MemoryStream();

  string documentName = jsonObject["document"];
  string result = Path.GetFileNameWithoutExtension(documentName);
  string fileName = result + "_downloaded.pdf";

  // Save the file on the server
  string serverFilePath = @"Path to where you need to save your file in the server";

  string filePath = Path.Combine(serverFilePath, fileName);

  using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
  {
    //Saving the new file in root path of application
    stream.CopyTo(fileStream);
    fileStream.Close();
  }
  return Content(documentBase);
}

Step 3: Set the PDF Viewer properties in your React app

Set the serviceUrl to point to your web service (for example, replace https://localhost:44396/pdfviewer with your server URL). Also set documentPath to the document URL you want to load.

import * as ReactDOM from 'react-dom';
import * as React from 'react';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, LinkAnnotation, BookmarkView, ThumbnailView,
         Print, TextSelection, Annotation, TextSearch, Inject, FormDesigner, FormFields} from '@syncfusion/ej2-react-pdfviewer';

function App() {
  return (<div>
    <div className='control-section'>
      {/* Render the PDF Viewer */}
        <PdfViewerComponent
          id="container"
          // Replace  correct PDF Document URL want to load
          documentPath="https://cdn.syncfusion.com/content/PDFViewer/flutter-succinctly.pdf"
          serviceUrl="https://localhost:44396/pdfviewer"
          style={{ 'height': '640px' }}>

              <Inject services={[ Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView, ThumbnailView,
                                  Print, TextSelection, TextSearch, FormDesigner, FormFields ]} />

        </PdfViewerComponent>
    </div>
  </div>);
}
const root = ReactDOM.createRoot(document.getElementById('sample'));
root.render(<App />);

View sample in GitHub

Download PDF file as a copy

The built-in toolbar includes a download option that saves the updated PDF to the user’s local file system. You can also trigger the same behavior programmatically by calling the viewer’s download() API.

import * as ReactDOM from 'react-dom/client';
import * as React from 'react';
import './index.css';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, LinkAnnotation, BookmarkView,
         ThumbnailView, Print, TextSelection, Annotation, TextSearch, FormFields, FormDesigner, Inject} from '@syncfusion/ej2-react-pdfviewer';

export function App() {

  function downloadClicked() {
    var viewer = document.getElementById('container').ej2_instances[0];
    viewer.download();
  }

return (<div>
    <div className='control-section'>
    <button onClick={downloadClicked}>Download</button>
        <PdfViewerComponent
          id="container"
          // Replace PDF_Succinctly.pdf with the actual document name that you want to load
          documentPath:"PDF_Succinctly.pdf"
          // Replace the "localhost:44396" with the actual URL of your server
          serviceUrl="https://localhost:44396/pdfviewer"
          style={{ 'height': '640px' }}>

              {/* Inject the required services */}
              <Inject services={[ Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView,
                                  ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner]} />
        </PdfViewerComponent>
    </div>
</div>);
}
const root = ReactDOM.createRoot(document.getElementById('sample'));
root.render(<App />);

Save modified PDF to a database

If your application stores PDF files in a database, you can save the updated PDF bytes back to the database from your web service. The following steps outline a typical server-side flow.

Step 1: Create the React sample viewer

Follow the getting-started guide to set up a basic Viewer instance.

Step 2: Update PdfViewerController.cs in the web service

  1. Create a web service project targeting .NET Core 3.0 or later (see the KB link above). Open the PdfViewerController.cs file in your web service project.

  2. Import required namespaces:

using System.IO;
using System.Data.SqlClient;
  1. Add configuration fields to your controller and read the connection string from configuration:
private IConfiguration _configuration;
public readonly string _connectionString;

public PdfViewerController(IWebHostEnvironment hostingEnvironment, IMemoryCache cache, IConfiguration configuration)
{
  _hostingEnvironment = hostingEnvironment;
  _cache = cache;
  _configuration = configuration;
  _connectionString = _configuration.GetValue<string>("ConnectionString");
}
  1. In the Download() method, convert the returned base64 document to bytes and insert it into your database (the example below uses parameterized commands to avoid SQL injection):
[HttpPost("Download")]
[Microsoft.AspNetCore.Cors.EnableCors("MyPolicy")]
[Route("[controller]/Download")]
public async Task<IActionResult> Download([FromBody] Dictionary<string, string> jsonObject)
{
  //Initialize the PDF Viewer object with memory cache object
  PdfRenderer pdfviewer = new PdfRenderer(_cache);

  string documentBase = pdfviewer.GetDocumentAsBase64(jsonObject);
  byte[] documentBytes = Convert.FromBase64String(documentBase.Split(",")[1]);

  string documentId = jsonObject["documentId"];
  string result = Path.GetFileNameWithoutExtension(documentId);
  string fileName = result + "_downloaded.pdf";

  string connectionString = _connectionString;

  using (SqlConnection connection = new SqlConnection(connectionString))
  {
    connection.Open();

    using (SqlCommand cmd = new SqlCommand("INSERT INTO Table (FileName, fileData) VALUES (@FileName, @fileData)", connection))
    {
      cmd.Parameters.AddWithValue("@FileName", fileName);
      cmd.Parameters.AddWithValue("@fileData", documentBytes);

      cmd.ExecuteNonQuery();
    }
    connection.Close();
  }
  return Content(documentBase);
}
  1. Add the connection string to appsettings.json:
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionString": "Your connection string for SQL Server"
}

NOTE

Replace Your connection string for SQL Server with your actual connection string.

NOTE

Ensure the System.Data.SqlClient package (or Microsoft.Data.SqlClient) is installed in your project. Use parameterized queries (as shown) and validate inputs to avoid SQL injection risks.

View sample in GitHub

Save to Cloud Storage Services

Each link below goes to a provider page with simple, step-by-step instructions and example code for saving the edited PDF to that cloud storage service.

Save PDF with or without annotations

The React PDF Viewer allows exporting the current PDF along with annotations, or exporting a clean version without annotations. This gives flexibility depending on workflow review mode, sharing, or securing final documents.

Save PDF with annotations

The PDF is exported with annotations and form fields by default. You can download a PDF using the download button in the built‑in toolbar or through the download API. See the download guide for further explanation.

Save PDF without annotations

The PDF can be exported without annotations by setting the skipDownload API to true in annotationSettings.

  • TS
  • <PdfViewerComponent
        id="pdfViewer"
        documentPath="https://cdn.syncfusion.com/content/pdf/form-filling-document.pdf"
        resourceUrl="https://cdn.syncfusion.com/ej2/32.2.5/dist/ej2-pdfviewer-lib"
        annotationSettings={{
            skipDownload: true
        }}
    >
        <Inject services={[Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, ThumbnailView,
            BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Print]} />
    </PdfViewerComponent>

    Save after restoring annotations

    PDFs can also be exported after importing annotations. The following code example uses the downloadStart event to cancel the download action and import the annotations from a JSON file before downloading the PDF document.

    import {
        PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation,
        ThumbnailView, BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner,
        PageOrganizer, Inject, Print, DownloadStartEventArgs
    } from '@syncfusion/ej2-react-pdfviewer';
    import { DataFormat, PdfDocument } from '@syncfusion/ej2-pdf';
    import { RefObject, useRef } from 'react';
    
    export default function App() {
        const viewerRef: RefObject<PdfViewerComponent> = useRef(null);
    
        const blobToBase64 = async (blob: Blob): Promise<string> => {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onerror = () => reject(reader.error);
                reader.onload = () => {
                    const dataUrl: string = reader.result as string;
                    const data: string = dataUrl.split(',')[1];
                    resolve(data);
                };
                reader.readAsDataURL(blob);
            });
        }
    
        const restoreAnnotations = async (data: string) => {
            try {            
                const fetchResponse: Response = await fetch("/pdf-succinctly.json", { headers: { Accept: "application/json" } });
                if (fetchResponse.ok) {
                    let document: PdfDocument = new PdfDocument(data);
                    let jsonData = await fetchResponse.json();
                    document.importAnnotations(btoa(JSON.stringify(jsonData)), DataFormat.json);
                    document.save(`${viewerRef.current.fileName}.pdf`);
                    document.destroy();
                }
                else {
                    throw new Error(`HTTP ${fetchResponse.status}`);
                }            
            }
            catch (error) {
                console.error(error);
            }
        }
    
        const handleImports = async () => {
            const blob: Blob = await viewerRef.current.saveAsBlob();
            const data: string = await blobToBase64(blob);
            await restoreAnnotations(data);
        }
    
        const onDownloadStart = async (args: DownloadStartEventArgs) => {
            args.cancel = true;
            await handleImports();
        };
    
        return (
            <div style={{ height: '640px' }}>
                <PdfViewerComponent
                    id="pdf-viewer"
                    ref={viewerRef}
                    documentPath="https://cdn.syncfusion.com/content/pdf/form-filling-document.pdf"
                    resourceUrl="https://cdn.syncfusion.com/ej2/32.2.5/dist/ej2-pdfviewer-lib"
                    downloadStart={onDownloadStart}
                >
                    <Inject services={[Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, ThumbnailView,
                        BookmarkView, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Print]} />
                </PdfViewerComponent>
            </div>
        );
    }

    See also