Menus
A menu is a list of items in sections, with a line between sections. Add one with addMenu(), and
open it from a button: a command with menu instead of run.
{
commands: [
{ id: 'acme:share', label: 'Share', icon: 'link', menu: 'share' },
{ id: 'acme:copy-link', label: 'Copy link', icon: 'copy', run: copyLink },
{ id: 'acme:email', label: 'Email a link', icon: 'message', run: emailLink },
],
layout: (layout) =>
layout
.addMenu('share', [['acme:copy-link', 'acme:email'], ['document:download']])
.add('acme:share', { to: 'main', section: 'end' }),
}Each row is a command, so it shows its icon, label and shortcut, is disabled when the command can’t run, and is gone when the command isn’t visible.
This menu goes to the document’s chapters, with a line before its last row:
Loading live preview…
import { Component } from '@angular/core';
import { EpdfPdfViewer, type ViewerConfig } from '@embedpdf/viewer-angular';
const welcome = '/pdfs/welcome.pdf';
@Component({
selector: 'demo-root',
imports: [EpdfPdfViewer],
template: `<epdf-pdf-viewer [src]="welcome" [config]="config" style="height: 100%" />`,
})
export class App {
readonly welcome = welcome;
readonly config: ViewerConfig = {
commands: [
{ id: 'acme:chapters', label: 'Chapters', icon: 'book', menu: 'chapters' },
{ id: 'acme:origins', label: 'Origins', run: ({ get }) => get('stage').goToPage(1) },
{ id: 'acme:timeline', label: 'Timeline', run: ({ get }) => get('stage').goToPage(2) },
{ id: 'acme:workflows', label: 'Workflows', run: ({ get }) => get('stage').goToPage(3) },
{ id: 'acme:cover', label: 'Back to the cover', run: ({ get }) => get('stage').goToPage(0) },
],
layout: (layout) =>
layout
.addMenu('chapters', [['acme:origins', 'acme:timeline', 'acme:workflows'], ['acme:cover']])
.add('acme:chapters', { to: 'main', section: 'end' }),
};
}Try it: open Chapters, the book at the end of the toolbar, and pick Timeline to go to the timeline on page 3. Back to the cover, under the line, goes back to the title page.
Where a menu opens#
You don’t choose. A menu opens away from the edge its bar sits on, toward the pages:
| The button is in | The menu opens |
|---|---|
| A bar at the top | Below it |
| A bar at the bottom | Above it |
| A bar at the start or end | Beside it, toward the pages |
| A floating bar | Away from the corner or edge it floats at |
| A bar over a selection | Away from the selection, so it never covers it, flipping when there’s no room |
When there’s no room on that side, it opens on the other. A menu can reach past the viewer’s edge, like a menu in any app, and it never goes off the screen. On a phone, every menu opens as a sheet from the bottom of the viewer.
Change a built-in menu#
The built-in menus are document, view, zoom, outline-item, attachment-item, comment-item and page. Add to them and remove
from them like a bar:
layout
.add('acme:export-word', { to: 'document', after: 'document:print' })
.remove('view:fullscreen', { from: 'document' });| Menu | Its button | What’s in it |
|---|---|---|
document | menu:document | Open (with the local engine), download, print; full screen |
view | menu:view | One page, two pages, cover page; vertical or horizontal scrolling, or page by page; rotate the view; full screen |
zoom | menu:zoom | 50% to 400%; zoom in and out, and the marquee zoom tool; fit page, fit width, automatic |
outline-item | menu:outline-item, on each row of the outline panel, and a right-click on the row | Add an item after or inside; rename, set the destination, properties; delete |
attachment-item | menu:attachment-item, on each file of the attachments panel, and a right-click on the file | Save, go to a page’s file; delete |
comment-item | menu:comment-item, on each card of the comments panel, and a right-click on the card | The thread’s status: accepted, rejected, cancelled, completed or none; delete the thread |
page | menu:page, on each page of the thumbnails panel and in its header, a right-click and a long press on a page | Rotate either way; insert a blank page or a PDF, duplicate; extract; delete |
Sections with a title#
A section is an array, or an object when it has a title:
layout.addMenu('export', [
{ title: 'Export as', items: ['acme:export-word', 'acme:export-excel'] },
['document:download'],
]);A menu in a menu#
An item whose command has a menu opens that menu beside it, as a submenu. On a phone, it slides
in over the first one, with a back button.
// acme:share has `menu: 'share'`, so it opens the share menu beside it
layout.add('acme:share', { to: 'document', after: 'document:download' });Choices#
A command that’s active is marked in a menu with the accent color, like an active toolbar button.
The view menu uses this for one page or two, and for the scrolling direction, so the current choice
is always marked.
Over a selection#
Two bars appear over what’s selected:
| Bar | Appears over | What’s in it |
|---|---|---|
selection | Selected text | Copy, highlight, underline, strike out |
annotation | Selected annotations | Comment, style, link, group, delete |
They’re bars, so the same edits work. Add your own action, or remove one:
layout
.add('acme:explain', { to: 'selection' })
.remove(['annotation:group', 'annotation:ungroup'], { from: 'annotation' });A selection bar appears when the selection is made, not while the mouse is still dragging. The bar for text sits above it, and the bar for annotations below them. Each flips to the other side when there’s no room, and on a touch screen the text bar keeps clear of the handles. Each item is shown only for a selection it works on: Comment isn’t offered on a link, and Group only when more than one annotation is selected.
The “More” menu#
When a bar runs out of room, what doesn’t fit goes into a “More” menu at its end, in the bar’s own order, with the bar’s groups as sections. The viewer builds it, so there’s nothing to set: change the bar, and the “More” menu follows.
Good to know#
Keyboard#
Arrow keys move through a menu, Enter picks, typing jumps to the first item that starts with
that letter, and Escape closes it and puts focus back on its button. Each command’s shortcut
shows next to its label.
Disabled or hidden#
A command that can’t run now, such as Copy with nothing selected, shows greyed out. A command
that’s not visible isn’t in the menu at all, and a section with nothing left disappears with its
line.
Your own menu component#
To draw a menu yourself, with your own rows, use Menu and MenuItem from Your own
components. They open the same way these do.
Your feedback goes directly to the documentation team.