Right-click (or the Menu key / Shift+F10) on selected text, an annotation, a citation, a figure, a link or the page. The library does not draw the menu: it tells you what is there and what can be done, and you render it with any menu component (bits-ui, melt, your own).
1. What is here: viewer.contextAt
Viewer.Viewport records the context of every contextmenu event in viewer.lastContext (keyboard-opened menus use the selection or the focused element). Stores add their facts through resolvers: Annotations.Root adds the annotations under the point (innermost first), Paper.Root the citation, cross-reference, figure and section. Add your own:
contextKind(ctx) returns the most specific target: selection › annotation › citation › link › figure › page.
2. What can be done: contextActions
Labels come from the viewer’s messages (setMessages / messages prop) and keys from the active keymap, so remapped shortcuts show up in the menu.
3. Rendering with bits-ui
The site’s PdfContextMenu recipe wraps Viewer.Viewport as the ContextMenu.Trigger (through the child snippet) and renders the groups, submenus and <kbd> hints:
Shortcuts everywhere
<Shortcut.Root action="markup.highlight" />renders the keys of an action as<kbd>(reflecting user overrides) — put it in tooltips, toolbars and menus so people learn them.shortcutGroups(viewer, store)returns the full, labelled reference — the site’sShortcutsDialogopens it with?.- One keymap drives everything:
<Viewer.Root keymap={{ 'view.zoomIn': ['mod+='], 'markup.highlight': ['y'] }}>;Annotations.Root keymapcan add to it.
Copy with formatting & extraction
viewer.document.richText(page, start, end)→{ plain, markdown, html }keeps bold / italic (inferred from the PDF’s font names) and fixes line-end hyphenation;copyRich(plain, html, markdown)puts both flavours on the clipboard.referenceToBibtex(reference, metadata?)builds a BibTeX entry from a parsed reference.- Region extraction is pluggable (
RegionExtractor):layoutExtractorrebuilds tables from the text layout (no dependencies);pdfOxideExtractor({ load: () => import('pdf-oxide-wasm'), getData })adapts the pdf_oxide WASM build.