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 renders no layer of its own — its widgets draw through the
annotation plugin's <PdfAnnotationLayer>, and whether they fill or drag is the
annotation plugin's lock mode. Locking the form category lets a click fall
through the widget to the field underneath; this toggle is a wrapper over that
setLocked call, so both plugins have to be registered and a layer rendered.
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 @pdfviewcn/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.