Skip to main content
The Velt Apryse WebViewer integration is documented for React. This guide covers the React integration only.

Setup

Step 1: Add Comment components

  • Add the Velt Comments component to the root of your app.
  • This component is required to render comments in your app.
  • Set the text mode prop to false to hide the default text comment tool.

Step 2: Install the Velt Apryse package

@veltdev/apryse-velt-comments lists @pdftron/webviewer as a peer dependency — install it yourself (the package won’t bring its own copy, to avoid running two WebViewer runtimes in the same browser):
Serve Apryse’s runtime assets Apryse’s WebViewer isn’t just JavaScript — it ships with a WebAssembly core, the Office Editor engine, and a UI shell (HTML/CSS/JS), all under node_modules/@pdftron/webviewer/public/. These are loaded at runtime over HTTP from a URL on your site (the path option you pass to WebViewer(...)), not via a JS import — so your bundler won’t pick them up on its own. You need to copy them into your app’s static folder so the browser can fetch them. Most teams automate this with a postinstall script:
Wire it up in package.json:
After install, the assets are at public/lib/webviewer/core/ (WASM + PDF/Office engines) and public/lib/webviewer/ui/ (WebViewer UI shell) — which is exactly what the path: 'lib/webviewer' option in WebViewer(...) (see Step 3) points to.

Step 3: Create an Apryse WebViewer component with Velt Comments

  • Attach the extension to the WebViewer instance once it’s created. The instance is then the handle that every addComment / renderComments call uses.
  • @pdftron/webviewer touches the DOM, so import it dynamically (only in the browser) to stay SSR-safe in Next.js, Remix, etc.

Step 4: Add a comment button to your WebViewer

  • Add a button that users can click to add comments after selecting text in the document.
  • Unlike DOM-based editors, Apryse selections live in the WebViewer’s canvas — clicking a button in the host page does not clear the selection, so no onMouseDown / preventDefault dance is needed. Just call addComment({ instance }).

Step 5: Call addComment to add a comment

  • Call this method to add a comment to the currently selected text in the WebViewer. You can use this when the user clicks on the comment button or presses a keyboard shortcut.
  • Params: AddCommentArgs. It has the following properties:
    • instance: The Apryse WebViewerInstance returned by WebViewer(...).
  • Returns: AddCommentResult or null. Resolves to null if no text is selected or the Velt SDK is not yet loaded. On success it returns:
    • veltAnnotationId: The Velt annotation id assigned by the SDK.
    • textEditorConfig: The durable logical anchor stored on the annotation ({ editorId, text, pageNumber, occurrence }).
To scope comments to a specific WebViewer (multi-viewer pages), set the editor id when you attach the extension: ApryseVeltComments.configure({ editorId: 'EDITOR_ID' }).attach(webViewerInstance). renderComments will then only paint annotations whose stored editorId matches.

Step 6: Render comments in the WebViewer

  • Use the useCommentAnnotations hook from @veltdev/react to get comment data from Velt and render it in the WebViewer.
  • Params: RenderCommentsArgs. It has the following properties:
    • instance: The Apryse WebViewerInstance.
    • commentAnnotations: Array of Comment Annotation objects from Velt.
The library uses a durable logical anchor (text + occurrence) per comment — anchors survive document edits, page reflow, and viewer ↔ docxEditor mode switches. Physical positions are re-derived at render time.

Step 7: Clean up when the component unmounts

  • ApryseVeltComments.configure(...).attach(instance) returns an AttachedExtension handle. Call detach() from your effect cleanup so every Apryse listener and per-instance cache is released.
  • If you switch documents inside the same WebViewer (e.g. via instance.UI.loadDocument(...)), you do not need to detach/re-attach — the extension listens for Apryse’s beforeDocumentLoaded / documentLoaded events and re-syncs the comment highlights automatically.

Step 8: Style the commented text

  • Comment highlights are rendered as positioned <div> elements inside <velt-comment-text> annotation overlays that Apryse manages on each page.
  • The default styles are set via inline !important rules, so to override them target the inner highlight class with a higher-specificity selector or !important.
<velt-comment-text> lives inside the <apryse-webviewer> shadow root, so global CSS automatically reaches it (the browser applies host-page styles into open shadow roots for unknown custom elements).

APIs

ApryseVeltComments.configure()

Creates the Velt Comments extension for the Apryse WebViewer. It exposes a configure(...).attach(instance) pattern — each .attach() returns a handle whose .detach() undoes everything for that instance.
  • Params: config?: ApryseVeltCommentsConfig
    • editorId?: string - Unique identifier for this WebViewer instance (for multi-viewer scenarios). Default: 'apryse'.
  • Returns: ApryseVeltComments (call .attach(instance) to wire it to a WebViewer, which returns an AttachedExtension)

addComment()

Creates a comment annotation for the currently selected text in the WebViewer.

renderComments()

Renders and highlights comment annotations in the WebViewer.