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

Angular PDF.js PDF viewer

The Angular PDF 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.

Step 1 - Set Up 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

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.

Step 2 - Configuration

The viewer has numerous 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.

Step 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 accordingly.

<! -- 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>

Step 4 - Replacing Widget Icons

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

<! -- 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 example above, replace /assets/icon/baseline-open_in_browser-24px.svg with your preferred image, or swap it out with Angular's mat-icon component (read more).

Step 5 - Changing the Widget or Toolbar Styling

Style widgets and the toolbar in the app.component.scss file. You can adjust the toolbar background, widget sizing or padding, the 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;
  }
}

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

This is a great solution for very basic viewing capabilities, where you're not concerned with rendering inconsistencies or failures in PDF.js Angular. If you need more robust functionality, such as annotation, form filling, or other features, you must implement them yourself. See our Guide to Evaluating PDF.js to learn more.

For 100% rendering reliability, hundreds of features out-of-the-box, and more granular control of UX, consider PDFTron’s WebViewer, a JavaScript PDF Viewer :

Check out our online demo.

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

Integrating 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

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, enter:

# 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.

Conclusion

Building a PDF Viewer with Angular and PDF.js is straightforward, but if you need more advanced features, 100% reliability, or high-fidelity rendering, open source is not always the best approach.

PDFTron WebViewer is a JavaScript-based PDF library with hundreds of features, support for 30+ file formats, with a proven rendering engine built right in, and is simple to integrate with Angular projects. Try our JavaScript PDF library today for free!

Check out our online demo or try it free .

If you have any questions about PDFTron's PDF SDK, please contact us !

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