EmbedPDF

Buttons & commands

Every button in the viewer runs a command: one action with a label, an icon, a shortcut, and what it does. A toolbar button, a menu row and a key press all run the same command, so they always agree. Add one of yours, then put it in the layout:

{
  commands: [
    {
      id: 'acme:approve',
      label: 'Approve',
      icon: 'check',
      shortcut: 'Mod+Enter',
      run: ({ documentId }) => approve(documentId),
    },
  ],
  layout: (layout) => layout.add('acme:approve', { to: 'main', section: 'end' }),
}

The button has a tooltip with its shortcut, moves into the “More” menu when the toolbar is full, and Ctrl+Enter (Cmd+Enter on a Mac) runs it while the viewer has focus.

Define a command#

FieldWhat it is
idA unique name. Start yours with your own prefix, such as acme:.
labelWhat people see, or labelKey for a translated label
iconAn icon’s name: the viewer’s or your own
shortcutA key, such as 'Mod+Shift+S', or a list of keys. Mod is Cmd on a Mac and Ctrl elsewhere.
shortcutInTextFieldstrue: its shortcut works in a text field in the viewer too, as Find’s does
runWhat it does
enabledWhen it can run. When it can’t, its button is greyed out.
activeWhen it shows as pressed, or checked in a menu
visibleWhen it shows at all
menuA menu it opens, instead of run
panelA panel it opens and closes, instead of run
requiresThe permissions it needs from the scope. Without them, it’s hidden.
categoriesThe features it belongs to, so disable turns it off with them. A name of your own makes a new feature.

A command is the same thing as in headless: see Commands & shortcuts.

Enabled, active and visible#

enabled, active and visible are functions of the viewer’s state. They get get, which gives you any plugin by its name, and the viewer asks them again whenever something changes, so a button is always right:

{
  id: 'acme:flag',
  label: 'Flag for review',
  icon: 'eye',
  enabled: ({ get }) => get('selection').hasSelection(),
  active: ({ documentId }) => flagged.has(documentId),
  run: ({ documentId }) => toggleFlag(documentId),
}

run gets the same: get, the viewer, and the documentId of the document it runs for.

Change what a built-in button does#

A command with a built-in id replaces the built-in one, everywhere it appears: the button, the menu row and the shortcut. This one makes Download save to your server instead:

{
  commands: [
    {
      id: 'document:download',
      run: async ({ viewer, documentId }) => {
        const bytes = await viewer.documents.download(documentId);
        await fetch(`/api/documents/${documentId}`, { method: 'PUT', body: bytes });
      },
    },
  ],
}

Give only the fields you change: the label, icon and shortcut stay the built-in ones.

Icons#

An icon is 24 × 24 SVG path data, drawn as a line, so Tabler and Lucide icons paste in as they are. Give a name to each of yours:

{
  icons: {
    send: ['M10 14L21 3', 'M21 3l-6.5 18a.5.5 0 0 1-1 0L10 14l-7-3.5a.5.5 0 0 1 0-1L21 3z'],
    logo: { paths: ['M4 4h16v16H4z'], fill: true },
  },
}

A string is one path, an array is several, and { paths, fill: true } fills them instead of drawing their outline. An icon with the name of a built-in one replaces it, everywhere.

Permissions#

A command that needs a permission from the scope says which, with requires. When the user doesn’t have it, the command is gone from every bar and menu, and its shortcut does nothing:

{
  id: 'acme:approve',
  label: 'Approve',
  icon: 'check',
  requires: ['doc.annotate.modify'],
  run: ({ documentId }) => approve(documentId),
}

The names are the scope’s permissions, listed on Permissions. The built-in commands already say what they need, so for a user whose scope doesn’t allow changes the editing tools are gone, and with notAllowed: 'disable' they show greyed out instead, with the reason in their tooltip. To leave a command out for everyone, disable it instead: disable: ['acme:approve'].

Keyboard shortcuts#

A command’s shortcut works while focus is anywhere inside the viewer, except in a text field, unless the command says shortcutInTextFields: true, as Find (search:find, Ctrl/Cmd+F) does. ? opens a sheet with every shortcut. Your shortcut wins over a built-in one with the same keys. Copying works the same way: Ctrl/Cmd+C, and Copy in the browser’s Edit menu, copy the viewer’s selected text only while focus is inside it, so the page keeps its own copying.

Run a command from code#

await viewer.commands.execute('zoom:fit-width');
await viewer.commands.execute('panel:search');

execute() resolves { status: 'executed' }, or { status: 'rejected', reason } when the command can’t run now.

Every built-in command#

CommandsWhat they do
document:open, document:download, document:printOpen another file, download, print
menu:document, menu:view, menu:zoomOpen a built-in menu
zoom:in, zoom:out, zoom:fit-width, zoom:fit-page, zoom:automaticZoom
zoom:50, zoom:100, zoom:150, zoom:200, zoom:400Zoom to a level
page:next, page:previous, page:first, page:last, page:go-toMove through pages
view:single-page, view:two-pages, view:cover-pagePages side by side
view:scroll-vertical, view:scroll-horizontalThe scrolling direction
view:rotate-clockwise, view:rotate-counterclockwise, view:fullscreenTurn the view, full screen
tool:pointer, tool:panSelect, or drag the pages
tool:note, tool:link, tool:highlight, tool:underline, tool:strikeout, tool:squigglyComment and mark up
tool:ink, tool:ink-highlight, tool:free-text, tool:callout, tool:insert-text, tool:replace-textDraw and write
tool:square, tool:circle, tool:line, tool:arrow, tool:polygon, tool:polylineShapes
tool:stamp, tool:image, tool:attachment, tool:signatureInsert
form:designSwitch form design on or off in the Form mode, with its sidebar
tool:text-field, tool:checkbox, tool:radio, tool:combo-box, tool:list-box, tool:button, tool:signature-fieldBuild a form
tool:redact, redaction:applyMark areas, then remove them for good
tool:distance, tool:perimeter, tool:area, measurement:calibrateMeasure
mode:view, mode:annotate, mode:shapes, mode:insert, mode:form, mode:redact, mode:measureSwitch mode
panel:<id>Open or close a panel
search:findOpen search with the cursor in its field (Ctrl/Cmd+F), with a search panel in the layout
history:undo, history:redoUndo and redo
selection:copy, selection:highlight, selection:underline, selection:strikeoutAct on selected text
annotation:comment, annotation:style, annotation:link, annotation:group, annotation:ungroup, annotation:deleteAct on selected annotations
help:shortcutsShow every shortcut (?)

Every tool you add to the annotation plugin gets its tool:<id> command too.

Good to know#

The viewer’s icons#

area, bold, book, calibrate, callout, check, circle, comment, copy, distance, dots, download, eye, file, fullscreen, group, hand, highlight, italic, line, link, lock, menu, message, palette, paperclip, perimeter, photo, plus, pointer, polygon, print, redact, ruler, save, search, settings, sidebar, signature, square, squiggly, strikethrough, text, trash, underline, ungroup, unlock, x, zigzag.

Enabled is for now, permissions are for good#

enabled is for what can’t run right now: nothing selected, nothing to undo. Its button is greyed out, because the user can change that. What the user may never do here is a permission: say so with requires, and the button isn’t there at all.

Was this page helpful?

Your feedback goes directly to the documentation team.