- PDF Viewer
- PDF Toolbar
- PDF More Actions Menu
- PDF Floating Toolbar
- PDF Document Tabs
- PDF View
- PDF Document Grid
- PDF Document Info
- PDF Page Navigation
- PDF Zoom Controls
- PDF Undo/Redo Buttons
- PDF Keyboard Shortcuts
- PDF Bookmark Sidebar
- PDF Thumbnail Sidebar
- PDF Search Panel
- PDF Attachment List
- PDF Annotation Layer
- PDF Annotation Toolbar
- PDF Annotation Inspector
- PDF Annotation Selection Menu
- PDF Annotation Sidebar
- PDF Comment
- PDF Comment Draft
- PDF Comment Button
- PDF Comment Sidebar
- PDF Redaction Toolbar
- PDF Capture Button
- PDF Form Fill Toggle
- PDF Signature Button
- PDF Stamp Button
Switch a document between filling out its AcroForm fields and repositioning them.
"use client";
import { createPluginRegistration } from "@embedpdf/core";About#
<PdfFormFillToggle /> switches a document between two modes for its interactive
form fields (AcroForm widgets — text boxes, checkboxes, radios, dropdowns):
- Fill mode (pressed) — the form is fillable. Clicking a field puts the cursor in it and typing lands in the input.
- Design mode (unpressed) — the same widgets behave as ordinary annotations you can select, move, and resize.
The form plugin doesn't render a layer of its own. Its field widgets render
through the annotation plugin's <PdfAnnotationLayer>, and whether they fill or
behave as annotations comes down to one thing: the annotation plugin's lock
mode. Locking the form category is what lets a click fall through the widget
to the field underneath. This toggle is a styled wrapper over exactly that —
the annotation capability's setLocked:
provides.setLocked(
fillMode
? { type: LockModeType.None }
: { type: LockModeType.Include, categories: ["form"] },
);Because it drives the annotation plugin, both plugins have to be registered and
an <PdfAnnotationLayer> rendered — the toggle is one control in that setup, not a
standalone widget.
This renders a disabled shell until both AnnotationPluginPackage and
FormPluginPackage are registered on the viewer. Registering
FormPluginPackage alone won't show fields — they render through the
annotation layer.
Installation#
pnpm dlx shadcn@latest add pdfcn/form-fill-toggle
Usage#
Register the annotation and form plugins.
import { createPluginRegistration } from "@embedpdf/core";
import {
AnnotationPluginPackage,
LockModeType,
} from "@embedpdf/plugin-annotation/react";
import { FormPluginPackage } from "@embedpdf/plugin-form/react";
// Outside the component — a new array identity on every render tears the
// engine down and rebuilds it, losing scroll and zoom state. Starting the
// annotation plugin locked to the `form` category opens the document already
// fillable rather than in design mode.
const plugins = [
createPluginRegistration(AnnotationPluginPackage, {
locked: { type: LockModeType.Include, categories: ["form"] },
}),
createPluginRegistration(FormPluginPackage),
];Render the annotation layer — the form fields render through it — and drop the toggle in the toolbar.
<PdfViewer
documents={[{ url: "/form.pdf" }]}
plugins={plugins}
className="h-[720px]"
>
<PdfToolbar>
<PdfFormFillToggle />
</PdfToolbar>
<PdfViewerContent
pageLayers={({ documentId, pageIndex }) => (
<PdfAnnotationLayer documentId={documentId} pageIndex={pageIndex} />
)}
/>
</PdfViewer>Examples#
Default#
The document opens in fill mode. Click a field and type; toggle off to switch to design mode, where the widgets become selectable annotations.
"use client";
import { createPluginRegistration } from "@embedpdf/core";Accessibility#
The control is a single toggle button labelled "Fill form", with a tooltip to match. Its pressed state reflects whether the document is in fill mode, so a screen reader announces the mode rather than leaving it to the icon.
Filling and moving fields both require a pointer, since a field is selected by clicking it on the page — there's no keyboard equivalent for placing the cursor in a specific widget.
API Reference#
PdfFormFillToggle#
A <Toggle /> carrying data-slot="pdf-form-fill-toggle". Accepts every prop
the underlying toggle takes; pressed, onPressedChange, aria-label, and the
default icon are managed internally but can be overridden.
The toggle reads and writes the annotation plugin's lock mode through
useAnnotation(documentId). Pressed sets { type: LockModeType.Include, categories: ["form"] } (fill mode); unpressed sets { type: LockModeType.None }
(design mode). It renders disabled whenever there's no active document or the
annotation plugin isn't registered.