Integrate WebViewer into a React App with Custom UI Enhancements

This sample demonstrates several features to customize WebViewer into a React app to render without <iFrame> , <button> elements for expanding functionality, and how to leverage the search APIs. The UI customization includes:

  • How to leverage Apryse's document renderer without an <iFrame>
  • How to define custom <button> elements and implement functionality from the Apryse SDK such as
    • Zoom In/Out
    • Drawing Rectangles
    • Select Tool
    • Creating and Applying Redactions
  • How to implement searching using DocViewer Search APIs

WebViewer provides a slick out-of-the-box responsive UI that enables you to view, annotate and manipulate PDFs and other document types inside any web project.

Click the button below to view the full project in GitHub.

1import React, { useRef, useEffect, useState } from 'react';
2import SearchContainer from './components/SearchContainer';
3import { ReactComponent as ZoomIn } from './assets/icons/ic_zoom_in_black_24px.svg';
4import { ReactComponent as ZoomOut } from './assets/icons/ic_zoom_out_black_24px.svg';
5import { ReactComponent as AnnotationRectangle } from './assets/icons/ic_annotation_square_black_24px.svg';
6import { ReactComponent as AnnotationRedact } from './assets/icons/ic_annotation_add_redact_black_24px.svg';
7import { ReactComponent as AnnotationApplyRedact} from './assets/icons/ic_annotation_apply_redact_black_24px.svg';
8import { ReactComponent as Search } from './assets/icons/ic_search_black_24px.svg';
9import { ReactComponent as Select } from './assets/icons/ic_select_black_24px.svg';
10import { ReactComponent as EditContent } from './assets/icons/ic_edit_page_24px.svg';
11import { ReactComponent as AddParagraph } from './assets/icons/ic_paragraph_24px.svg';
12import { ReactComponent as AddImageContent } from './assets/icons/ic_add_image_24px.svg';
13import './App.css';
14
15const App = () => {
16 const viewer = useRef(null);
17 const scrollView = useRef(null);
18 const searchTerm = useRef(null);
19 const searchContainerRef = useRef(null);
20
21 const [documentViewer, setDocumentViewer] = useState(null);
22 const [annotationManager, setAnnotationManager] = useState(null);
23 const [searchContainerOpen, setSearchContainerOpen] = useState(false);
24 const [isInContentEditMode, setIsInContentEditMode] = useState(false);
25
26 const Annotations = window.Core.Annotations;
27
28 // if using a class, equivalent of componentDidMount
29 useEffect(() => {
30 const Core = window.Core;
31 Core.setWorkerPath('/webviewer');
32 Core.enableFullPDF();
33
34 const documentViewer = new Core.DocumentViewer();
35 documentViewer.setScrollViewElement(scrollView.current);
36 documentViewer.setViewerElement(viewer.current);
37 documentViewer.enableAnnotations();
38 documentViewer.loadDocument('/files/demo.pdf');
39
40 setDocumentViewer(documentViewer);
41
42 documentViewer.addEventListener('documentLoaded', () => {
43 console.log('document loaded');
44 documentViewer.setToolMode(documentViewer.getTool(Core.Tools.ToolNames.EDIT));
45 setAnnotationManager(documentViewer.getAnnotationManager());
46 });
47 }, []);
48
49 const zoomOut = () => {
50 documentViewer.zoomTo(documentViewer.getZoomLevel() - 0.25);
51 };
52
53 const zoomIn = () => {
54 documentViewer.zoomTo(documentViewer.getZoomLevel() + 0.25);
55 };
56
57 const startEditingContent = () => {
58 const contentEditManager = documentViewer.getContentEditManager();
59 contentEditManager.startContentEditMode();
60 setIsInContentEditMode(true);
61 }
62
63 const endEditingContent = () => {
64 setIsInContentEditMode(false);
65 documentViewer.setToolMode(documentViewer.getTool(window.Core.Tools.ToolNames.EDIT));
66 const contentEditManager = documentViewer.getContentEditManager();
67 contentEditManager.endContentEditMode();
68 }
69
70 const addParagraph = () => {
71 if (isInContentEditMode) {
72 const addParagraphTool = documentViewer.getTool(window.Core.Tools.ToolNames.ADD_PARAGRAPH);
73 documentViewer.setToolMode(addParagraphTool);
74 } else {
75 alert('Content Edit mode is not enabled.')
76 }
77 };
78
79 const addImageContent = () => {
80 if (isInContentEditMode) {
81 const addImageContentTool = documentViewer.getTool(window.Core.Tools.ToolNames.ADD_IMAGE_CONTENT);
82 documentViewer.setToolMode(addImageContentTool);
83 } else {
84 alert('Content Edit mode is not enabled.')
85 }
86 };
87
88 const createRectangle = () => {
89 documentViewer.setToolMode(documentViewer.getTool(window.Core.Tools.ToolNames.RECTANGLE));
90 };
91
92 const selectTool = () => {
93 documentViewer.setToolMode(documentViewer.getTool(window.Core.Tools.ToolNames.EDIT));
94 };
95
96 const createRedaction = () => {
97 documentViewer.setToolMode(documentViewer.getTool(window.Core.Tools.ToolNames.REDACTION));
98 };
99
100 const applyRedactions = async () => {
101 const annotationManager = documentViewer.getAnnotationManager();
102 annotationManager.enableRedaction();
103 await annotationManager.applyRedactions();
104 };
105
106 return (
107 <div className="App">
108 <div id="main-column">
109 <div className="center" id="tools">
110 <button onClick={zoomOut}>
111 <ZoomOut />
112 </button>
113 <button onClick={zoomIn}>
114 <ZoomIn />
115 </button>
116 <button onClick={startEditingContent} title="Switch to edit mode">
117 <EditContent />
118 </button>
119 <button onClick={addParagraph} title="Add new paragraph">
120 <AddParagraph />
121 </button>
122 <button onClick={addImageContent} title="Add new content image">
123 <AddImageContent />
124 </button>
125 <button onClick={endEditingContent} title="End edit mode">
126 Finish Editing
127 </button>
128 <button onClick={createRectangle}>
129 <AnnotationRectangle />
130 </button>
131 <button onClick={createRedaction} title="Create Redaction">
132 <AnnotationRedact />
133 </button>
134 <button onClick={applyRedactions} title="Apply Redactions">
135 <AnnotationApplyRedact />
136 </button>
137 <button onClick={selectTool}>
138 <Select />
139 </button>
140 <button
141 onClick={() => {
142 // Flip the boolean
143 setSearchContainerOpen(prevState => !prevState);
144 }}
145 >
146 <Search />
147 </button>
148 </div>
149 <div className="flexbox-container" id="scroll-view" ref={scrollView}>
150 <div id="viewer" ref={viewer}></div>
151 </div>
152 </div>
153 <div className="flexbox-container">
154 <SearchContainer
155 Annotations={Annotations}
156 annotationManager={annotationManager}
157 documentViewer={documentViewer}
158 searchTermRef={searchTerm}
159 searchContainerRef={searchContainerRef}
160 open={searchContainerOpen}
161 />
162 </div>
163 </div>
164 );
165};
166
167export default App;
168

Did you find this helpful?

Trial setup questions?

Ask experts on Discord

Need other help?

Contact Support

Pricing or product questions?

Contact Sales