Advertisement
  1. Web Design
  2. HTML/CSS
  3. HTML

How to Create a JavaScript PDF Viewer

Scroll to top

The Portable Document Format, or PDF for short, is ideal for sharing documents containing lots of precisely formatted text and images, especially if they're likely to be printed or read offline. Although most modern browsers can display PDF files, they do so using a PDF viewer that runs in an independent tab or window, forcing users to leave your website.

PDF.js is an open-source JavaScript library that allows you to parse and render PDF files right inside your web pages. In this tutorial, I'll show you how to use it to create a fully fledged custom JavaScript PDF viewer from scratch.

If you're adding a PDF viewer to your site, you might also be interested in a professional Flipbook plugin. JavaScript flipbooks showcase your content in a digital flipbook form, using page-flipping effects, zoom, and support for multiple content types.

1. Creating a User Interface

Let's start by creating a new web page and adding the usual HTML5 boilerplate code to it.

1
<!doctype html>
2
 
3
<html lang="en">
4
<head>
5
  <meta charset="utf-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
  <title>My PDF Viewer</title>
8
</head>
9
<body>
10
     
11
</body>
12
</html>

Next, inside the <body>, create a <div> element that can serve as a container for our PDF viewer.

1
<div id="my_pdf_viewer">
2
     
3
</div>

At the heart of our JavaScript PDF viewer will be an HTML5 <canvas> element. We'll be rendering the pages of our PDF files inside it. So add the following code inside the <div> element.

1
<div id="canvas_container">
2
    <canvas id="pdf_renderer"></canvas>
3
</div>

To keep things simple, we'll be rendering only one page inside the canvas at any given time. We will, however, allow users to switch to the previous page or the next page by pressing a button. Additionally, to display the current page number, and to allow users to jump to any page they desire, our interface will have an input field.

1
<div id="navigation_controls">
2
    <button id="go_previous">Previous</button>
3
    <input id="current_page" value="1" type="number"/>
4
    <button id="go_next">Next</button>
5
</div>

To support zoom operations, add two more buttons to the interface: one to zoom in and one to zoom out.

1
<div id="zoom_controls">  
2
    <button id="zoom_in">+</button>
3
    <button id="zoom_out">-</button>
4
</div>

At the end of this section, the web page code looks like this.

1
<!doctype html> 
2
<html lang="en">
3
<head>
4
  <meta charset="utf-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
  <title>My PDF Viewer</title>
7
</head>
8
<body>
9
     <div id="my_pdf_viewer">
10
        <div id="canvas_container">
11
            <canvas id="pdf_renderer"></canvas>
12
        </div>
13
14
        <div id="navigation_controls">
15
            <button id="go_previous">Previous</button>
16
            <input id="current_page" value="1" type="number"/>
17
            <button id="go_next">Next</button>
18
        </div>
19
20
        <div id="zoom_controls">  
21
            <button id="zoom_in">+</button>
22
            <button id="zoom_out">-</button>
23
        </div>
24
    </div>
25
</body>
26
</html>

2. Getting PDF.js

Now that a bare-bones user interface for our JavaScript PDF viewer is ready, let's add PDF.js to our web page. Because the latest version of the library is available on CDNJS, we can do so by simply adding the following lines towards the end of the web page.

1
<script

2
    src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js">
3
</script>

If you prefer to use a local copy of the library, you can download it from the pdfjs-dist repository.

3. Loading a PDF File

Before we start loading a PDF file, let's create a simple JavaScript object to store the state of our PDF viewer. Inside it, we'll have three items: a reference to the PDF file itself, the current page index, and the current zoom level.

1
<script>
2
    var myState = {
3
        pdf: null,
4
        currentPage: 1,
5
        zoom: 1
6
    }
7
 
8
    // more code here

9
</script>

At this point, we can load our PDF file by calling the getDocument() method of the pdfjsLib object, which runs asynchronously.

1
pdfjsLib.getDocument('./my_document.pdf').then((pdf) => {
2
 
3
    // more code here
4
 
5
});

Note that the getDocument() method internally uses an XMLHttpRequest object to load the PDF file. This means that the file must be present either on your own web server or on a server that allows cross-origin requests.

If you don't have a PDF file handy, you can get the one I'm using from Wikipedia.

Once the PDF file has been loaded successfully, we can update the pdf property of our state object.

1
myState.pdf = pdf;

Lastly, add a call to a function named render() so that our PDF viewer automatically renders the first page of the PDF file. We'll define the function in the next step.

1
render();

4. Rendering a Page

By calling the getPage() method of the pdf object and passing a page number to it, we can get a reference to any page in the PDF file. For now, let's pass the currentPage property of our state object to it. This method too returns a promise, so we'll need a callback function to handle its result.

Accordingly, create a new function called render() containing the following code:

1
function render() {
2
    myState.pdf.getPage(myState.currentPage).then((page) => {
3
 
4
        // more code here
5
 
6
    });
7
}

To actually render a page, we must call the render() method of the page object available inside the callback. As arguments, the method expects the 2D context of our canvas and a PageViewport object, which we can get by calling the getViewport() method. Because the getViewport() method expects the desired zoom level as an argument, we must pass the zoom property of our state object to it.

1
var canvas = document.getElementById("pdf_renderer");
2
var ctx = canvas.getContext('2d');
3
 
4
var viewport = page.getViewport(myState.zoom);

The dimensions of the viewport depend on the original size of the page and the zoom level. In order to make sure that the entire viewport is rendered on our canvas, we must now change the size of our canvas to match that of the viewport. Here's how:

1
canvas.width = viewport.width;
2
canvas.height = viewport.height;

At this point, we can go ahead and render the page.

1
page.render({
2
    canvasContext: ctx,
3
    viewport: viewport
4
});

Putting it all together, the whole source code looks like this.

1
<!doctype html>
2
 
3
<html lang="en">
4
<head>
5
  <meta charset="utf-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
  <title>My PDF Viewer</title>
8
  <script

9
    src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js">
10
  </script>
11
</head>
12
<body>
13
     <div id="my_pdf_viewer">
14
        <div id="canvas_container">
15
            <canvas id="pdf_renderer"></canvas>
16
        </div>
17
18
        <div id="navigation_controls">
19
            <button id="go_previous">Previous</button>
20
            <input id="current_page" value="1" type="number"/>
21
            <button id="go_next">Next</button>
22
        </div>
23
24
        <div id="zoom_controls">  
25
            <button id="zoom_in">+</button>
26
            <button id="zoom_out">-</button>
27
        </div>
28
    </div>
29
30
    <script>
31
        var myState = {
32
            pdf: null,
33
            currentPage: 1,
34
            zoom: 1
35
        }
36
     
37
        pdfjsLib.getDocument('./my_document.pdf').then((pdf) => {
38
     
39
            myState.pdf = pdf;
40
            render();
41
42
        });
43
44
        function render() {
45
            myState.pdf.getPage(myState.currentPage).then((page) => {
46
         
47
                var canvas = document.getElementById("pdf_renderer");
48
                var ctx = canvas.getContext('2d');
49
     
50
                var viewport = page.getViewport(myState.zoom);
51
52
                canvas.width = viewport.width;
53
                canvas.height = viewport.height;
54
         
55
                page.render({
56
                    canvasContext: ctx,
57
                    viewport: viewport
58
                });
59
            });
60
        }
61
    </script>
62
</body>
63
</html>

If you try opening the web page in a browser, you should now be able to see the first page of your PDF file.

DemoDemoDemo

You may have noticed that the size of our PDF viewer currently depends on the size of the page being rendered and the zoom level. This is not ideal because we don't want the layout of our web page to be affected while users interact with the PDF viewer. 

To fix this, all we need to do is give a fixed width and height to the <div> element encapsulating our canvas and set its overflow CSS property to auto. This property, when necessary, adds scroll bars to the <div> element, allowing users to scroll both horizontally and vertically.

Add the following code inside the <head> tag of the web page:

1
<style>
2
    #canvas_container {
3
        width: 800px;
4
        height: 450px;
5
        overflow: auto;
6
    }
7
</style>

You are, of course, free to change the width and height or even use media queries to make the <div> element match your requirements.

Optionally, you can include the following CSS rules to make the <div> element seem more distinct:

1
#canvas_container {
2
    background: #333;
3
    text-align: center;
4
    border: solid 3px;
5
}

If you refresh the web page now, you should see something like this on your screen:

Demo With BackgroundDemo With BackgroundDemo With Background

5. Changing the Current Page

Our JavaScript PDF viewer is currently capable of showing only the first page of any PDF file given to it. To allow users to change the page being rendered, we must now add click event listeners to the go_previous and go_next buttons we created earlier.

Inside the event listener of the go_previous button, we must decrement the currentPage property of our state object, making sure that it doesn't fall below 1. After we do so, we can simply call the render() function again to render the new page.

Additionally, we must update the value of the current_page text field so that it displays the new page number. The following code shows you how:

1
document.getElementById('go_previous')
2
    .addEventListener('click', (e) => {
3
    if(myState.pdf == null|| myState.currentPage == 1) 
4
    return;
5
       
6
    myState.currentPage -= 1;
7
    document.getElementById("current_page").value = myState.currentPage;
8
    render();
9
});

Similarly, inside the event listener of the go_next button, we must increment the currentPage property, while ensuring that it doesn't exceed the number of pages present in the PDF file, which we can determine using the numPages property of the _pdfInfo object.

1
document.getElementById('go_next')
2
    .addEventListener('click', (e) => {
3
    if(myState.pdf == null || myState.currentPage > myState.pdf._pdfInfo.numPages) 
4
    return;
5
         
6
    myState.currentPage += 1;
7
    document.getElementById("current_page").value = myState.currentPage;
8
    render();
9
});

Lastly, we must add a key press event listener to the current_page text field so that users can directly jump to any page they desire by simply typing in a page number and hitting the Enter key. Inside the event listener, we need to make sure that the number the user has entered is both greater than zero and less than or equal to the numPages property.

1
document.getElementById('current_page')
2
    .addEventListener('keypress', (e) => {
3
    if(myState.pdf == null) return;
4
 
5
    // Get key code
6
    var code = (e.keyCode ? e.keyCode : e.which);
7
 
8
    // If key code matches that of the Enter key
9
    if(code == 13) {
10
        var desiredPage = document.getElementById('current_page').valueAsNumber;
11
                         
12
        if(desiredPage >= 1 && desiredPage <= myState.pdf._pdfInfo.numPages) {
13
            myState.currentPage = desiredPage;
14
            document.getElementById("current_page").value = desiredPage;
15
            render();
16
        }
17
    }
18
});

Our PDF viewer can now display any page of the PDF file.

Page ControlsPage ControlsPage Controls

6. Changing the Zoom Level

Because our render() function already uses the zoom property of the state object while rendering a page, adjusting the zoom level is as easy as incrementing or decrementing the property and calling the function.

Inside the on-click event listener of the zoom_in button, let's increment the zoom property by 0.5.

1
document.getElementById('zoom_in')
2
    .addEventListener('click', (e) => {
3
    if(myState.pdf == null) return;
4
    myState.zoom += 0.5;
5
6
    render();
7
});

And inside the on-click event listener of the zoom_out button, let's decrement the zoom property by 0.5.

1
document.getElementById('zoom_out')
2
    .addEventListener('click', (e) => {
3
    if(myState.pdf == null) return;
4
    myState.zoom -= 0.5;
5
    
6
    render();
7
});

You are free to add upper and lower bounds to the zoom property, but they are not required.

This is what it looks like when it's all put together.

1
<!doctype html>
2
 
3
<html lang="en">
4
<head>
5
  <meta charset="utf-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1">
7
  <title>My PDF Viewer</title>
8
  <script

9
    src="http://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js">
10
  </script>
11
12
  <style>
13
      #canvas_container {
14
          width: 800px;
15
          height: 450px;
16
          overflow: auto;
17
      }
18
19
      #canvas_container {
20
        background: #333;
21
        text-align: center;
22
        border: solid 3px;
23
      }
24
  </style>
25
</head>
26
<body>
27
     <div id="my_pdf_viewer">
28
        <div id="canvas_container">
29
            <canvas id="pdf_renderer"></canvas>
30
        </div>
31
32
        <div id="navigation_controls">
33
            <button id="go_previous">Previous</button>
34
            <input id="current_page" value="1" type="number"/>
35
            <button id="go_next">Next</button>
36
        </div>
37
38
        <div id="zoom_controls">  
39
            <button id="zoom_in">+</button>
40
            <button id="zoom_out">-</button>
41
        </div>
42
    </div>
43
44
    <script>
45
        var myState = {
46
            pdf: null,
47
            currentPage: 1,
48
            zoom: 1
49
        }
50
     
51
        pdfjsLib.getDocument('./my_document.pdf').then((pdf) => {
52
     
53
            myState.pdf = pdf;
54
            render();
55
56
        });
57
58
        function render() {
59
            myState.pdf.getPage(myState.currentPage).then((page) => {
60
         
61
                var canvas = document.getElementById("pdf_renderer");
62
                var ctx = canvas.getContext('2d');
63
     
64
                var viewport = page.getViewport(myState.zoom);
65
66
                canvas.width = viewport.width;
67
                canvas.height = viewport.height;
68
         
69
                page.render({
70
                    canvasContext: ctx,
71
                    viewport: viewport
72
                });
73
            });
74
        }
75
76
        document.getElementById('go_previous').addEventListener('click', (e) => {
77
            if(myState.pdf == null || myState.currentPage == 1) 
78
              return;
79
            myState.currentPage -= 1;
80
            document.getElementById("current_page").value = myState.currentPage;
81
            render();
82
        });
83
84
        document.getElementById('go_next').addEventListener('click', (e) => {
85
            if(myState.pdf == null || myState.currentPage > myState.pdf._pdfInfo.numPages) 
86
               return;
87
            myState.currentPage += 1;
88
            document.getElementById("current_page").value = myState.currentPage;
89
            render();
90
        });
91
92
        document.getElementById('current_page').addEventListener('keypress', (e) => {
93
            if(myState.pdf == null) return;
94
         
95
            // Get key code

96
            var code = (e.keyCode ? e.keyCode : e.which);
97
         
98
            // If key code matches that of the Enter key

99
            if(code == 13) {
100
                var desiredPage = 
101
                document.getElementById('current_page').valueAsNumber;
102
                                 
103
                if(desiredPage >= 1 && desiredPage <= myState.pdf._pdfInfo.numPages) {
104
                    myState.currentPage = desiredPage;
105
                    document.getElementById("current_page").value = desiredPage;
106
                    render();
107
                }
108
            }
109
        });
110
111
        document.getElementById('zoom_in').addEventListener('click', (e) => {
112
            if(myState.pdf == null) return;
113
            myState.zoom += 0.5;
114
            render();
115
        });
116
117
        document.getElementById('zoom_out').addEventListener('click', (e) => {
118
            if(myState.pdf == null) return;
119
            myState.zoom -= 0.5;
120
            render();
121
        });
122
    </script>
123
</body>
124
</html>

Our PDF viewer is ready. If you refresh the web page again, you should be able to view all the pages present in the PDF file and also zoom in to or zoom out of them.

Zoom DemoZoom DemoZoom Demo

Premium Flipbook Plugins From CodeCanyon

You might also be interested in a professional Flipbook plugin. JavaScript flipbooks showcase your content in a digital flipbook form, using page-flipping effects, zoom, and support for multiple content types. CodeCanyon is a marketplace for all kinds of code, including premium JavaScript widgets and jQuery plugins. It's the best place to find jQuery flipbook plugins.

jquery Flipbookjquery Flipbookjquery Flipbook

Let's dive into five top jQuery flipbook plugins you can buy from CodeCanyon:

1. WowBook, a Flipbook jQuery Plugin

WowBook is appropriately named. This JavaScript PDF viewer is adaptable and easy to use. It includes three demos that are ready for you to use once you get them set up. It's also responsive, so your PDF will look great on multiple screen sizes.

WowBook JavaScript PDF Viewer DownloadWowBook JavaScript PDF Viewer DownloadWowBook JavaScript PDF Viewer Download

2. Diamond FlipBook: Query

There's a reason why Diamond FlipBook is so highly rated. It's a simple viewer that looks great on your site. It does away with the now obsolete Flash Player and can support an unlimited number of pages. You'll also like the lazy loading that keeps your site and PDF loading fast.

Diamond jQuery FlipBook PluginDiamond jQuery FlipBook PluginDiamond jQuery FlipBook Plugin

3. Responsive FlipBook jQuery

Fully driven by HTML and jQuery, this responsive flipbook download is perfect for PDFs. It comes with zoom features, as well as:

  • table of contents
  • adaptable to mobile devices
  • double pages
  • video support
  • over 30 background patterns

If you need a JavaScript PDF viewer that's packed with features for you and your site's visitors, try Responsive FlipBook jQuery.

Responsive FlipBook jQueryResponsive FlipBook jQueryResponsive FlipBook jQuery

4. Newspaper Flipbook jQuery

Newspaper Flipbook is a top jQuery PDF viewer on CodeCanyon. Not only does this download include free support, but it also comes with free updates so your content stays looking its best. It supports right-to-left languages and documents. You can also add individual pages as JPGs in the HTML code.

Newspaper Flipbook jQuery PluginNewspaper Flipbook jQuery PluginNewspaper Flipbook jQuery Plugin

5. Real3D FlipBook jQuery Plugin

We round out our list of premium flipbook plugins with Real3D FlipBook. It's a jQuery PDF viewer download that has a lot of style. You can choose from:

  • mobile optimized
  • retina-ready icons
  • fully customizable

Check out the demos online and you'll see why it's a top-rated jQuery flipbook plugin to try in 2021.

Real3D FlipBook jQuery PluginReal3D FlipBook jQuery PluginReal3D FlipBook jQuery Plugin

Conclusion

You now know how to use PDF.js to create a custom JavaScript PDF viewer for your website. With it, you can confidently offer a seamless user experience while displaying your organization's brochures, white papers, forms, and other documents generally meant to be distributed as hard copies.

You can learn more about PDF.js on the official GitHub repo.

You might also be interested in a professional flipbook plugin. JavaScript flipbooks showcase your content in a digital flipbook form, using page-flipping effects, zoom, and support for multiple content types. CodeCanyon is a marketplace for all kinds of code, including premium JavaScript widgets and jQuery plugins. It's the best place to find jQuery flipbook plugins.

jquery Flipbookjquery Flipbookjquery Flipbook
Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.