In this post we'll show you how to display PDFs in Angular 5+ by using the PDF.js-based ng2-pdf-viewer component, and then wrapping it with a custom UI. Here's what it will look like:

The viewer includes a handful of widgets, making it ideal for basic PDF viewing use cases:

  • Opening a local file
  • Toggling document outline
  • Rotating left/right
  • Zooming in/out
  • Toggling fit page
  • Toggling the display of all pages
  • Previous/next page navigation
  • Searching text

The source code for this project is available in our Git repo.

linkStep 1 - Setup Your Project

Once you've created the directory for your project, clone and launch the repo from the Node command line:

# command line
git clone https://github.com/PDFTron/ng5-pdf-viewer-ui.git
cd ng5-pdf-viewer-ui
npm i
ng serve --open

You can change the PDF file that's loaded by default in the viewer by replacing the pdftron-sdk.pdf filename in app.component.ts:

// file: ng5-pdf-viewer-ui/src/app/app.component.ts
pdfSrc: string | PDFSource | ArrayBuffer = '../assets/pdftron-sdk.pdf';

You now have a basic PDF viewer! The next step is customizing the UI...

linkStep 2 - Configuration

The viewer has a number of configurable options in app.component.html:

<! -- file: ng5-pdf-viewer-ui/src/app/app.component.html -- >
  <pdf-viewer
    [src]="pdfSrc"
    [(page)]="page"
    [rotation]="rotation"
    [original-size]="originalSize"
    [fit-to-page]="fitToPage"
    (after-load-complete)="afterLoadComplete($event)"
    [zoom]="zoom"
    [show-all]="showAll"
    [stick-to-page]="stickToPage"
    [render-text]="renderText"
    [external-link-target]="'blank'"
    [autoresize]="autoresize"
    (error)="onError($event)"
    (on-progress)="onProgress($event)"
    (page-rendered)="pageRendered($event)"
  ></pdf-viewer>

We won't drill into this too much because the README for ng2-pdf-viewer explains this quite thoroughly.

linkStep 3 - Removing Widgets From The UI

The code for displaying widgets is located in app.component.html, with each widget wrapped inside <span> tags. To remove (or re-order) the widgets, simply find the tag and adjust as needed.

<! -- file: ng5-pdf-viewer-ui/src/app/app.component.html -- >
<input
  (change)="onFileSelected()"
  type="file"
  id="file"
  class="d-none"
  accept=".pdf"
/>
<div class="toolbar d-flex">
  <span
    class="my-icon"
    [inlineSVG]="'/assets/icon/baseline-open_in_browser-24px.svg'"
    (click)="openLocalFile()"
    title="Open File"
  ></span>
  <span
    class="my-icon"
    [ngClass]="{ active: isOutlineShown }"
    [inlineSVG]="'/assets/icon/baseline-toc-24px.svg'"
    (click)="toggleOutline()"
    title="Toggle Outline"
  ></span>
  <span
    class="my-icon"
    [inlineSVG]="'/assets/icon/baseline-rotate_left-24px.svg'"
    (click)="rotate(-90)"
    title="Rotate Left"
  ></span>
  <span
    class="my-icon"
    [inlineSVG]="'/assets/icon/baseline-rotate_right-24px.svg'"
    (click)="rotate(90)"
    title="Rotate Right"
  ></span>
  <span
    class="my-icon"
    [inlineSVG]="'/assets/icon/baseline-zoom_in-24px.svg'"
    (click)="incrementZoom(0.1)"
    title="Zoom In"
  ></span>
  <span
    class="my-icon"
    [inlineSVG]="'/assets/icon/baseline-zoom_out-24px.svg'"
    (click)="incrementZoom(-0.1)"
    title="Zoom Out"
  ></span>
  <span
    class="my-icon"
    [ngClass]="{ active: fitToPage }"
    [inlineSVG]="'/assets/icon/baseline-insert_drive_file-24px.svg'"
    (click)="fitToPage = !fitToPage"
    title="Toggle Fit Page"
  ></span>
  <span
    class="my-icon"
    [ngClass]="{ active: showAll }"
    [inlineSVG]="'/assets/icon/baseline-multi-pages-24px.svg'"
    (click)="showAll = !showAll"
    title="Toggle Show All"
  ></span>

  <ng-container *ngIf="!showAll">
    <span
      class="my-icon ml-auto"
      [inlineSVG]="'/assets/icon/baseline-navigate_before-24px.svg'"
      (click)="incrementPage(-1)"
      title="Previous Page"
    ></span>
    <div>
      <input
        type="number"
        class="page-num"
        placeholder="Page"
        [(ngModel)]="page"
        pattern="-?[0-9]*(\.[0-9]+)?"
      />
      <span *ngIf="pdf">of {{ pdf.numPages }}</span>
    </div>
    <span
      class="my-icon"
      [inlineSVG]="'/assets/icon/baseline-navigate_next-24px.svg'"
      (click)="incrementPage(1)"
      title="Next Page"
    ></span>
  </ng-container>

  <label
    class="my-icon ml-auto"
    [inlineSVG]="'/assets/icon/baseline-search-24px.svg'"
    for="searchbox"
    title="Search.."
  ></label>
  <input
    #queryInp
    type="text"
    id="searchbox"
    name="searchbox"
    class="searchbox mr-5"
    placeholder="Search..."
    [value]="pdfQuery"
    (input)="searchQueryChanged($event.target.value)"
    (keyup.enter)="searchQueryChanged(queryInp.value)"
  />
</div>

For example, delete this code to remove the Document Outline toggle:

<! -- file: ng5-pdf-viewer-ui/src/app/app.component.html -- >
  <span
    class="my-icon"
    [ngClass]="{ active: isOutlineShown }"
    [inlineSVG]="'/assets/icon/baseline-toc-24px.svg'"
    (click)="toggleOutline()"
    title="Toggle Outline"
  ></span>

linkStep 4 - Replacing Widget Icons

Each widget icon is referenced individually from app.component.html, so it's easy to swap out the SVG with whatever image you need:

<! -- file: ng5-pdf-viewer-ui/src/app/app.component.html -- >
  <span
    class="my-icon"
    [inlineSVG]="'/assets/icon/baseline-open_in_browser-24px.svg'"
    (click)="openLocalFile()"
    title="Open File"
  ></span>

In the above example, replace /assets/icon/baseline-open_in_browser-24px.svg with your preferred image. Or you could swap them out with Angular's mat-icon component (read more).

linkStep 5 - Changing Widget or Toolbar Styling

Widgets and the toolbar can be styled in the app.component.scss file. Here we can adjust the background of the toolbar, widget sizing or padding, search box transition animation, and more.

/* file: ng5-pdf-viewer-ui/src/app/app.component.scss  */
.toolbar {
  background: #303030;
  padding: 10px;
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  z-index: 9999;
  span {
    color: white;
  }
}
.my-icon {
  margin: 0 7px;
  cursor: pointer;
  &:hover {
    opacity: 0.5;
  }
  &.active {
    opacity: 0.5;
  }
  &.active:hover {
    opacity: 1;
  }
}
.page-num {
  width: 50px;
  border: 0;
  margin-right: 2px;
  text-align: center;
}
.searchbox {
  width: 0;
  opacity: 0;
  transition: all 0.3s ease-out;
  border: 0px;
  padding: 0 3px;
  &:focus,
  &:active {
    outline: 0;
    box-shadow: none;
  }
}
.searchbox:focus {
  opacity: 1;
  width: 200px;
}
.pdf-body {
  margin-top: 46px;
}
input {
  &:focus,
  &:active {
    outline: 0;
    box-shadow: none;
  }
}
.outline {
  position: fixed;
  left: 0;
  top: 0;
  padding: 60px 5px 5px;
  height: 100vh;
  width: 250px;
  z-index: 9000;
  box-shadow: 3px 0px 5px 0px rgba(0, 0, 0, 0.75);
  background: white;
  ul {
    padding-left: 25px;
  }
}

You're done! You now have a basic Angular PDF viewer that matches your app's look-and-feel.

This is a great solution if you just need basic viewing capabilities, and you're not too concerned with the rendering inconsistencies or failures that come with PDF.js. If you need more robust functionality, like annotation, form filling, or others, you would have to implement them yourself.

For 100% rendering reliability, hundreds of features out-of-the-box, and more granular control of UX, consider PDFTron WebViewer:

  • View, annotate, and collaborate in real-time
  • Watermark, stamp, form fill, sign, search, and more
  • Client-side PDF editing (without a server)
  • Document security, DRM, encryption, redaction
  • Overprint, ICC color management, color separation
  • PDF, MS Office, and 30+ formats

Check out our online demo.

Also, it's easy to integrate into your Angular project...

linkIntegrating PDFTron WebViewer Into Angular Projects

Start by cloning our WebViewer Angular sample project:

# command line
git clone https://github.com/PDFTron/webviewer-angular-sample.git
cd webviewer-angular-sample

Then sign up for a free trial, and download the latest version of WebViewer. Once downloaded, copy the files from the WebViewer/lib folder and paste them to your project's src/assets/webviewer folder.

Then from the command line:

# command line
npm install
npm start

And that's it! You've now got a robust and reliable PDF viewer that's easy to customize.

linkConclusion

Building a PDF Viewer with Angular and PDF.js can be straightforward, but once you start needing more advanced features, 100% reliability, or high-fidelity rendering, open source may not be best approach.

PDFTron WebViewer is a JavaScript-based PDF library with hundreds of features, support for 30+ file formats, has a proven rendering engine built right in, and it's simple to integrate with Angular projects.

Check out our online demo or try it free.

If you have any questions about PDFTron's PDF SDK, please feel free to get in touch!

You can find the source code for this blog post at Github.