Add Nutrient Web SDK demo: full host-app shell around the viewer - #193
Merged
Merged
Conversation
A complete, standalone Vite + React + TypeScript app that showcases a fully custom UI around the Web SDK: custom top toolbar, draggable ink and text toolbars, side file explorer with drag-and-drop PDF uploads, a four-tab signature dialog, drag-and-drop form field placement, and a custom Form Creator property editor mounted into the SDK's slot. The SDK is loaded from the CDN via a script tag (pspdfkit-web@1.15.0), so no pspdfkit-lib copy step is required. biome.json is updated to opt the new example out of repo-wide formatting, matching the convention of every other example under web/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@sashamilenkovic @sc0 This is ready for you. |
ritz078
reviewed
Jun 9, 2026
ritz078
approved these changes
Jun 18, 2026
ritz078
left a comment
Contributor
There was a problem hiding this comment.
Two items with no single line to anchor to:
web/viewer/README.mdnot updated.AGENTS.md(Runnable Local Examples) requires updating the nearest category README so a new example is discoverable; the catalog currently lists onlymulti-tab.- No CI builds or typechecks this example —
typecheck.ymlis scoped toplayground/**and the demo sits inbiome.json's ignore list, sotsc -b && vite buildisn't exercised in CI. Matches repo norms (multi-tab is the same); just verify the build locally before merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's special about this demo
Most existing Web SDK examples in this repo show one feature: a single custom button, a single custom tooltip, a single replacement slot. They live inside the SDK's chrome.
This demo does the opposite — it hides the SDK's chrome and rebuilds a complete document workspace around the viewer, in the style of a host application like Dropbox's PDF UI. The viewer is just a content surface; the toolbar, file explorer, signing flow, form-creator panel, and drawing/text tools are all host-app code talking to the SDK through its instance API.
That's the angle this example covers that no other example in the repo does: it stress-tests the app/viewer boundary end-to-end and shows that customer-owned UI around the SDK is a viable path, not just per-component customization.
The six integration patterns it demonstrates
The API surfaces it exercises across the boundary
Slot replacement: `ui.tools.main`, `ui.tools.contextual`, `ui.signatures.create`, `ui.signatures.list`, `ui.formCreator.propertyEditor`, `annotationTooltipCallback`.
Instance methods: `setUI`, `setViewState`, `applyOperations`, `history.undo`/`redo`, `setAnnotationPresets`, `setCurrentAnnotationPreset`, `contentDocument`, `transformContentClientToPageSpace`, `createAttachment`, `create`, `update`, `delete`, `getSelectedAnnotations`, `setSelectedAnnotations`, `getFormFields`, `getAnnotations`, `exportPDF`, `InteractionMode.*`.
Annotation/form model: `Annotations.WidgetAnnotation`, `Annotations.ImageAnnotation` (with `isSignature: true`), `FormFields.TextFormField`, `FormFields.CheckBoxFormField`, `FormOption`, `Geometry.Rect`, `Geometry.Point`.
This breadth across one app is the point — it shows that all the pieces a customer needs to build a full host-app shell are present and that they compose.
Why this matters
This example was originally built as a validation example for the headless / API-first strategy: prove that the SDK is usable as an embeddable viewer surface inside a customer-owned UI, not only as a closed UI box that can be poked at the edges. As a side benefit, the demo surfaced an API ergonomics gap in slot callbacks (which then drove a follow-up SDK change) — exactly the kind of feedback this category of example is meant to produce.
What's rebuilt vs. consumed
Notes
Test plan