Skip to content

Editor

Scope: React viewer toolkit — editor layer (@scaryterry/pdfium/react/editor).

The editor is still additive, but the flagship path is no longer a hand-assembled stack. Start with PDFEditor, then drop to lower-level editor pieces only when you need to replace part of the shipped shell.

The flagship Vite /editor route now uses this contract directly:

  • PDFEditor keeps PDFViewer as the document frame.
  • The shipped document/view top bar, left editing tool rail, editor overlay, editor-aware annotations panel, and dedicated redactions panel are wired for you.
  • Lower-level editor exports remain public for partial replacement, not mandatory setup.
import { PDFEditor } from '@scaryterry/pdfium/react/editor';
export function EditorScreen() {
return <PDFEditor />;
}

PDFEditor defaults to the flagship editor posture:

  • panels: thumbnails, annotations, and redactions
  • initial panel: annotations
  • initial panel visibility: 'desktop-only' so narrow viewports start with the document primary
  • showAnnotations={false} so the passive annotation layer does not compete with interactive editing
  • bufferPages={2} for steadier editing interactions

The shipped shell also reuses the same toolbar, panel, and dialog theme tokens as PDFViewer, so editor chrome themes through the standard --pdfium-toolbar-*, --pdfium-panel-*, and --pdfium-dialog-* variables instead of a separate editor-only skin.

The default shell is intentionally split by task:

  • top bar: page navigation, zoom, search, undo/redo, save, and secondary view actions under More
  • left tool rail: selection, text, draw, shapes, stamp, and redact
  • active-tool action bar: on-canvas defaults for the current creation tool, plus a quick return to select mode. It docks automatically on coarse-pointer layouts instead of covering the page.
  • free-text editing: free-text annotations can be re-edited inline after creation from the selected-object bar, and the inline editor keeps typing isolated from viewer/editor shortcuts so text entry does not leak into document commands.
  • free-text typography: the shipped text defaults and selected-text style surfaces expose a constrained standard-font set (Helvetica, Times, and Courier families with bold/italic variants), plus size and colour, so free-text stays portable through save/reload instead of relying on arbitrary local fonts.
  • text selection bubble: highlight, underline, and strikeout actions appear when the user selects real page text
  • selected-annotation action bar: on-canvas style, duplicate, overlap picking, arrange, and delete actions stay attached to the current object instead of a hidden inspector section. It docks automatically on coarse-pointer layouts and for genuinely small selected objects so overlap-heavy editing stays readable.
  • left panels: thumbnails, a page-local annotations workspace for selection-aware editing, and a dedicated redactions workspace for review/apply
  • EditorProvider for tool state, selection, dirty tracking, and history
  • a shipped document/view command bar that keeps navigation and save visible without mixing in every editing mode
  • a shipped left tool rail so editing tools no longer compete with document navigation in the top bar
  • a shipped on-canvas active-tool surface so creation defaults stay near the document instead of buried in side chrome
  • renderDefaultEditorPageOverlay as the interactive page-overlay path
  • DefaultEditorAnnotationsPanel inside the left annotations panel so selection-aware editing stays in the main viewer shell
  • DefaultEditorRedactionsPanel inside a dedicated redactions panel so document-scope redaction review does not pollute page-local annotation inspection

That means the canonical editor route no longer needs local provider plumbing, a local overlay bridge, or a second inspector column.

Use PDFEditor first, then customise one seam at a time:

  • children appends extra content after the shipped top-bar document commands.
  • toolbarProps customises the shipped top-bar shell.
  • toolbarControlsProps customises save behaviour for the shipped top-bar save path.
  • classNames extends the viewer shell contract with toolRail and pageChrome, so you can style the shipped editor-only chrome without replacing it.
  • toolRailProps and pageChromeProps forward lightweight className / style hooks to the shipped tool rail and active-tool bar.
  • renderToolbar, renderSearch, renderToolRail, renderPageChrome, and renderPanelSidebar let you replace the shipped editor shell surfaces one seam at a time while keeping PDFEditor as the surrounding frame.
  • panels replaces or extends the left-panel set. If you keep the built-in 'annotations' entry, PDFEditor swaps in the shipped editor-aware annotations panel automatically. Add createDefaultEditorRedactionsPanelEntry() when you want the shipped redactions workflow in a manual composition.
  • sidebar={<MySidebar />} adds an explicit secondary sidebar only when you intentionally want one.
  • sidebarProps opts into DefaultEditorSidebar for advanced split-shell layouts. It is not part of the default editor shell.
  • renderPageOverlay adds extra overlay content beneath the shipped editor overlay.
  • editorProviderProps customises EditorProvider without rebuilding the shell.

If you need to replace the overlay stack, own the layout outright, or split the sidebar across multiple regions, drop to the lower-level composition. That lower-level path stays public, but it is intentionally more manual than the shipped PDFEditor shell:

If you only want to replace one shell region, prefer the render slots first. They keep the default frame, provider, and viewer/editor synchronisation intact:

<PDFEditor
classNames={{ toolRail: 'my-editor-tool-rail', pageChrome: 'my-editor-page-chrome' }}
toolRailProps={{ style: { backdropFilter: 'blur(24px)' } }}
renderPageChrome={() => <MyCanvasChrome />}
/>
import { DefaultToolbar, DefaultToolbarDownloadButton, PDFViewer } from '@scaryterry/pdfium/react';
import {
DefaultEditorAnnotationsPanel,
DefaultEditorRedactionsPanel,
DefaultEditorToolbarControls,
EditorProvider,
createDefaultEditorAnnotationsPanelEntry,
createDefaultEditorRedactionsPanelEntry,
renderDefaultEditorPageOverlay,
} from '@scaryterry/pdfium/react/editor';
export function CustomEditorScreen() {
return (
<EditorProvider>
<PDFViewer
panels={['thumbnails', createDefaultEditorAnnotationsPanelEntry(), createDefaultEditorRedactionsPanelEntry()]}
initialPanel="annotations"
showAnnotations={false}
bufferPages={2}
renderPageOverlay={renderDefaultEditorPageOverlay}
>
<DefaultToolbar leadingChildren={<DefaultEditorToolbarControls />}>
<DefaultToolbarDownloadButton />
</DefaultToolbar>
</PDFViewer>
</EditorProvider>
);
}
NeedAPINotes
Canonical shipped editor routePDFEditorFastest path to the flagship editor shell.
Live tool state and historyuseEditor()Reads the active tool, selection, dirty state, and undo/redo actions.
Viewer/editor mode syncuseEditorInteractionBridge()Keeps pointer mode, text selection, and editor tools in sync.
Viewer navigation outside PDFVieweruseEditorViewerNavigation()Reads current page and page count from direct viewer context or the shipped editor bridge.
Shipped page-overlay rendererrenderDefaultEditorPageOverlayCanonical renderPageOverlay helper for manual PDFViewer composition.
Shipped page-overlay componentDefaultEditorPageOverlayLower-level overlay component when you want to wrap or style the shipped renderer yourself.
Shipped editor annotations panelDefaultEditorAnnotationsPanelLeft-panel annotations view that upgrades selection detail into mutable editor controls.
Shipped annotations panel entrycreateDefaultEditorAnnotationsPanelEntry()Drops the shipped editor-aware annotations panel into manual PDFViewer compositions.
Shipped redactions panelDefaultEditorRedactionsPanelDedicated review/apply workspace for marked redactions with current-page actions and document-wide context.
Shipped redactions panel entrycreateDefaultEditorRedactionsPanelEntry()Drops the shipped redactions workflow into manual PDFViewer compositions.
Lower-level toolbar extensionDefaultEditorToolbarControlsManual composition helper for custom PDFViewer + DefaultToolbar shells. Useful when you are intentionally not using PDFEditor.
Page overlay editingEditorOverlayMount through renderPageOverlay; pass page geometry and current annotations.
Save workflowuseEditorSave(document)Flushes pending commits, saves the document, and marks the session clean.
Optional split-shell sidebarDefaultEditorSidebarAdvanced-only sidebar helper when you intentionally want a second column for custom layouts.
Selection-driven property editingAnnotationPropertyPanelLow-level selection editor when you want to own the annotation-resolution flow yourself.
Page insertion, movement, deletionusePageManagement() + PageManagementPanelLow-level page controls when you are prepared to design the surrounding UX yourself.
Cross-page redaction totalsuseRedactionSummary(document)Recomputes only pages whose revision changed, which is useful for custom editor status UI.
  • Markup tools should stay text-selection-first. Let users select real text, then trigger highlight/underline/strikeout.
  • Stack-order, overlap picking, and duplicate/delete actions should stay attached to the selected annotation itself, not buried inside the annotations workspace.
  • Common colour and border changes should be reachable from quick presets before falling back to raw inputs.
  • Free-text should stay truly editable after creation. Keep inline editing on the page surface and make sure keyboard input remains local to the text editor instead of triggering global document actions.
  • Destructive redaction apply should be explicit and confirmed in UI. Marking happens from the tool/rail flow; review and apply should live in the dedicated redactions workspace, not the page-local annotations workspace.
  • Save should stay disabled until the editor is dirty.
  • Undo and redo should remain available on the main path, not hidden in a secondary panel.
  • Editing tools should stay off the main document bar. Keep navigation/view commands in the top bar, editing modes in the left rail, and routine creation defaults near the canvas unless you have a very strong reason to collapse them together.

The shipped editor path is designed to stay usable without a mouse:

  • Escape returns active editor tools to the neutral pointer/select posture instead of leaving drawing tools sticky.
  • V returns the editor to the neutral posture and synchronises the viewer’s built-in text-selection control.
  • Ctrl/Cmd + Z and Ctrl + Y / Ctrl/Cmd + Shift + Z drive the shipped editor undo/redo history without requiring extra document listeners in user code.
  • Ctrl/Cmd + S triggers the shipped save path in PDFEditor / DefaultEditorToolbarControls, so the public editor shell owns save instead of deferring to the browser.
  • Undo/redo shortcuts defer to native text editing when focus is inside inputs or contenteditable regions, so property editing and free-text editing keep their local editing affordances.
  • The shipped toolbar, left annotations workspace, and viewer shell all use the shared PDFium focus-ring tokens, so replacing one surface should preserve the same visible focus language.

If you replace PDFEditor with manual composition, preserve those same rules unless you have a strong reason to change them.

  • PDFViewer for the base viewer shell that the editor extends
  • Headless for building custom editor chrome from headless bindings
  • Styling for theming editor components with CSS variables