Menus
<ngx-extended-pdf-viewer>
allows you to customize the toolbar and the menu of the PDF viewer.
You can:
- re-arrange the pre-defined items any way you like
- replace existing items by custom items - including your own icons, texts, and tooltips
- and add your own buttons, menu items, and even menus, implementing custom functions I can't even imagine
But how to document this feature?
I'm afraid you can't avoid reading the sourcecode of the UI. You find it in the GitHub repository of ngx-extended-pdf-viewer.
Nonetheless, I'm optimistic I can give you a head start with a couple of demos and a few hints:
- First of all, this interactive demo shows a few example implementations.
- The default UI naturally forms a tree. Below, you'll find a high-level abstraction of this tree. Your customization doesn't have to follow this structure. It's just the default.
- The customization hooks defined by allow you to modify certain subtrees. Currently there are nine hooks:
[customToolbar]
allows you to modify the entire black bar above the PDF document.[customFreeFloatingBar]
allows you to add your own toolbar. The original use-case is a toolbar floating above the PDF file. But if you're familiar with CSS magic, you're probably not limited to that.[customSecondaryToolbar]
represents the menu at the right-hand side of the PDF viewer.[customFindbar]
allows you to define your own findbar.[customFindbarButtons]
allows you to modify the entire find bar (the black bar that's shown after typing CTRL+F).[customFindbarInputArea]
is responsible for a small part of the find bar: the input field and the previous/next buttons.[customSidebar]
defines your own sidebar. See the custom sidebar demo.[customThumbnail]
See the custom thumbnails demo.[customPdfViewer]
is your door to modify everything except the CSS imports.
- The underlying PDF framework, pdf.js, recognizes the buttons and menu items by their id. If you want to modify an existing functionality, keep in mind you have to provide the id. Otherwise, pdf.js might raise an exception, and your custom button won't work.
- However, most buttons are component you can either use or copy. You can see the full list of toolbar buttons in the GitHub repository of ngx-extended-pdf-viewer.
- I'm sure there's a lot of headroom for improvements. Don't hesitate to report any shortcoming on the bugtracker of ngx-extended-pdf-viewer.
Toolbar
The toolbar is the black bar containing the buttons above the PDF file.
Legend: The red text tells you which id the component renders internally. When you use the component, don't add the id. Otherwise, the id is used twice. In many cases, this causes errors. However, since version 18, most buttons replaced the pdf.js implementation by an Angular implementation, so the ids aren't as important as they used to be in earlier versions.
Breaking Change in version 22: Some of the ids have changed: #print is now #printButton, and #download is now #downloadButton.
- <pdf-toolbar custom content: [customToolbar] ℹ >
- <div id="toolbarViewer" >
- <div id="toolbarViewerLeft" >
- <pdf-toggle-sidebar id="sidebarToggle" ℹ >
- <pdf-find-button id="viewFind" ℹ >
- <pdf-paging-area >
- <pdf-first-page id="primaryFirstPage" ℹ >
- <pdf-previous-page id="previous" ℹ >
- <pdf-page-number id="pageNumber" ℹ >
- <pdf-next-page id="next" ℹ >
- <pdf-last-page id="primaryLastPage" ℹ >
- <pdf-zoom-toolbar >
- <pdf-zoom-out id="zoomOut" ℹ >
- <pdf-zoom-in id="zoomIn" ℹ >
- <pdf-zoom-dropdown id="scaleSelect" ℹ >
- <div id="toolbarViewerRight" >
- <pdf-document-properties id="documentProperties" ℹ >
- <pdf-no-spread id="spreadNone" ℹ >
- <pdf-odd-spread id="spreadOdd" ℹ >
- <pdf-even-spread id="spreadEven" ℹ >
- <pdf-single-page-mode id="scrollPage" ℹ >
- <pdf-vertical-scroll-mode id="scrollVertical" ℹ >
- <pdf-horizontal-scroll id="scrollHorizontal" ℹ >
- <pdf-wrapped-scroll-mode id="scrollWrapped" ℹ >
- <pdf-infinite-scroll id="infiniteScroll" ℹ >
- <pdf-book-mode id="book-mode" ℹ >
- <pdf-hand-tool id="primaryCursorHandTool" ℹ >
- <pdf-select-tool id="primaryCursorSelectTool" ℹ >
- <pdf-rotate-page-cw id="primaryPageRotateCw" ℹ >
- <pdf-rotate-page-ccw id="primaryPageRotateCcw" ℹ >
- <pdf-presentation-mode id="presentationMode" ℹ >
- <pdf-open-file id="openFile" ℹ >
- <pdf-print id="print" ℹ >
- <pdf-download id="download" ℹ >
- <pdf-editor >
- <pdf-stamp-editor id="editorStamp" ℹ >
- <pdf-text-editor id="editorFreeText" ℹ >
- <pdf-ink-editor id="editorInk" ℹ >
- <pdf-toggle-secondary-toolbar id="secondaryToolbarToggle" ℹ >
Findbar
The findbar becomes visible after hitting CTRL+F
.
- <pdf-findbar >
- <div class="findbar hidden doorHanger" ... id="findbar" ℹ custom content: [customFindbarButtons] ℹ >
- <pdf-find-input-area custom content: [customFindbarInputArea] ℹ >
- <pdf-search-input-field id="findInput / findInputMultiline" ℹ >
- <pdf-find-previous id="findPrevious" ℹ >
- <pdf-find-next id="findNext" ℹ >
- <pdf-find-highlight-all id="findHighlightAll" ℹ >
- <pdf-find-highlight-all id="findCurrentPage" ℹ >
- <pdf-find-match-case id="findMatchCase" ℹ >
- <pdf-find-entire-word id="findEntireWord" ℹ >
- <pdf-match-diacritics id="findMatchDiacritics" ℹ >
- <pdf-find-results-count id="findResultsCount" ℹ >
- <pdf-findbar-message-container id="findMsg" ℹ >
Secondary menu (since version 18)
Since version 18, almost every button is able to move dynamically from the toolbar to the secondary menu. The idea is to move buttons from the toolbar to the secondary menu until the toolbar fits on the screen, so small displays can still show all buttons.
Every toolbar button has a show<ButtonName>
attribute which defines the breakpoint of the button. If the screen is wider than the breakpoint, the button is displayed in the toolbar. Otherwise it's displayed in the secondary menu. There are also two special values: always-visible
means the button is never moved to the secondary menu. Conversely, always-in-secondary-menu
means the button always hides in the secondary menu.
There's an interactive live-demo at the responsive design page of this showcase.
If you use the <pdf-shy-button>
component to define your custom buttons they also benefit from responsive design. However, there's a catch: if you're using the <pdf-shy-button>
, you can use the action
attribute to define custom logic. Basically, the action
attribute is treated like a fat arrow function - and that means it's inheriting the this
reference from the PdfShyButton
class. The constructor of your button component is never called, and neither is ngOnInit
. Probably that sounds more confusing than it is, so don't worry - it's easy to implement custom "shy" buttons. Just keep in mind that this is not what you might expect.
Adding custom buttons to the toolbar and/or the secondary menu
The <pdf-shy-button>
allows you to benefit from seamless integration into the toolbar and the secondary menu. A typical shy button looks like so:
<pdf-shy-button
[cssClass]="'always-in-secondary-menu' | responsiveCSSClass"
title="Infinite scroll"
primaryToolbarId="infiniteScroll"
l10nId="infinite_scroll"
[toggled]="pageViewMode == 'infinite-scroll'"
[action]="onClick"
l10nLabel="pdfjs-infinite-scroll-button-label"
[order]="3400"
[closeOnClick]="false"
image="<svg aria-hidden='true'
focusable='false'
xmlns='http://www.w3.org/2000/svg'
height= '24' viewBox= '0 -960 960 960'
width='24'>
<path d= '...'/>
</svg>"
>
</pdf-shy-button>
The clumsy [cssClass]
definition allows you to define the breakpoint using a shortcut. Legal values are always-visible
, always-in-secondary-menu
, xxs
, xs
, sm
, md
, lg
, xl
, and xxl
. xxl
means the button is only visible in the toolbar on very large screens, while xxs
means it's visible on fairly small screens.
The two l10n
attributes use the translation tables of pdf.js. They're useless for you unless you can use one of the pre-defined texts of the viewer.properties file. In most cases, [title]
should to the trick just as well.
[order]
determines where the button appears in the secondary menu. The default buttons use increments of 100, so you can insert 99 custom menu items between two default menu items. If the button shows in the toolbar, its position is determined by the position in the source code (plus CSS - in other words, it's exactly the behavior you'd expect).
The [action]
attribute is a bit tricky. You can't use this in the event listener method because the event listener is used both for the toolbar (this
is available here) and the secondary menu (this
is undefined here). I'm sure I've selected a clumsy solution, but here's my current approach:
export class PdfInfiniteScrollComponent implements OnDestroy {
@Input()
public pageViewMode: PageViewModeType;
@Output()
public pageViewModeChange = new EventEmitter<PageViewModeType>();
public onClick?: () => void;
constructor() {
const emitter = this.pageViewModeChange;
this.onClick = () => {
setTimeout(() => {
emitter.emit('infinite-scroll');
});
};
}
public ngOnDestroy(): void {
this.onClick = undefined;
}
}
The key idea is to define the event listener in the constructor, where you can capture this in a constant.
Secondary menu (before version 18)
Important: This section describes how the seondary menu worked in older versions. The old customizations should still work in version 18+, but I recommend migrating to the new approach because it's both simpler and more flexible.
The secondary toolbar is the menu that opens on the right-hand side. It contains many buttons of the primary toolbar. On small displays, widgets are shifted from the primary toolbar to the secondary toolbar until the primary toolbar fits on the screen. Similarly, when the window size gets larger, many items are shifted from the secondary toolbar to the primary toolbar.
- <pdf-secondary-toolbar custom content: [customSecondaryToolbar] ℹ >
- <div class="secondaryToolbar hidden doorHangerRight" id="secondaryToolbar" ℹ >
- <button title="Switch to Presentation Mode" id="secondaryPresentationMode" ℹ >
- <button title="Open (file)" id="secondaryOpenFile" ℹ >
- <button title="Print" id="secondaryPrint" ℹ >
- <button title="Download" id="secondaryDownload" ℹ >
- <button title="Go to First Page" id="firstPage" ℹ >
- <button title="Go to Last Page" id="lastPage" ℹ >
- <button title="Rotate Clockwise" id="pageRotateCw" ℹ >
- <button title="Rotate Counterclockwise" id="pageRotateCcw" ℹ >
- <button title="Enable Text Selection Tool" id="cursorSelectTool" ℹ >
- <button title="Enable Hand Tool" id="cursorHandTool" ℹ >
- <button title="Use Vertical Scrolling" id="scrollVertical" ℹ >
- <button title="Use Horizontal Scrolling" id="scrollHorizontal" ℹ >
- <button title="Use Wrapped Scrolling" id="scrollWrapped" ℹ >
- <button title="Do not join page spreads" id="spreadNone" ℹ >
- <button title="Join page spreads starting with odd-numbered pages" id="spreadOdd" ℹ >
- <button title="Join page spreads starting with even-numbered pages" id="spreadEven" ℹ >
- <button title="Document Properties…" id="documentProperties" ℹ >