EmbedPDF

Form Plugin

The Form Plugin adds interactive support for PDF AcroForm widgets. It lets users type into text fields, toggle checkboxes and radio buttons, work with dropdowns and list boxes, and read or set form values programmatically.

Form widgets render through the Annotation Plugin’s <AnnotationLayer />, so the form plugin must be registered alongside the annotation plugin and its interaction dependencies.

Installation

npm install @embedpdf/plugin-form @embedpdf/plugin-annotation @embedpdf/plugin-interaction-manager @embedpdf/plugin-selection @embedpdf/plugin-history

Registration

Register the annotation dependencies first, then the annotation plugin, then the form plugin:

<script setup lang="ts"> import { createPluginRegistration } from '@embedpdf/core'; import { EmbedPDF } from '@embedpdf/core/vue'; import { DocumentManagerPluginPackage } from '@embedpdf/plugin-document-manager/vue'; import { ViewportPluginPackage } from '@embedpdf/plugin-viewport/vue'; import { ScrollPluginPackage } from '@embedpdf/plugin-scroll/vue'; import { RenderPluginPackage } from '@embedpdf/plugin-render/vue'; import { ZoomPluginPackage, ZoomMode } from '@embedpdf/plugin-zoom/vue'; import { InteractionManagerPluginPackage } from '@embedpdf/plugin-interaction-manager/vue'; import { SelectionPluginPackage } from '@embedpdf/plugin-selection/vue'; import { HistoryPluginPackage } from '@embedpdf/plugin-history/vue'; import { AnnotationPluginPackage, LockModeType } from '@embedpdf/plugin-annotation/vue'; import { FormPluginPackage } from '@embedpdf/plugin-form/vue'; const plugins = [ createPluginRegistration(DocumentManagerPluginPackage, { initialDocuments: [{ url: '/form.pdf' }], }), createPluginRegistration(ViewportPluginPackage), createPluginRegistration(ScrollPluginPackage), createPluginRegistration(RenderPluginPackage), createPluginRegistration(ZoomPluginPackage, { defaultZoomLevel: ZoomMode.FitPage, }), createPluginRegistration(InteractionManagerPluginPackage), createPluginRegistration(SelectionPluginPackage), createPluginRegistration(HistoryPluginPackage), createPluginRegistration(AnnotationPluginPackage, { locked: { type: LockModeType.Include, categories: ['form'] }, }), createPluginRegistration(FormPluginPackage), ]; </script>

Usage

Render form fields

Form widgets appear through <AnnotationLayer />:

<template> <Scroller :document-id="documentId"> <template #default="{ page }"> <PagePointerProvider :document-id="documentId" :page-index="page.pageIndex"> <RenderLayer :document-id="documentId" :page-index="page.pageIndex" /> <SelectionLayer :document-id="documentId" :page-index="page.pageIndex" /> <AnnotationLayer :document-id="documentId" :page-index="page.pageIndex" /> </PagePointerProvider> </template> </Scroller> </template>

Read current form values

<script setup lang="ts"> import { ref, onMounted, onUnmounted } from 'vue'; import { useFormCapability } from '@embedpdf/plugin-form/vue'; const props = defineProps<{ documentId: string }>(); const { provides: formCapability } = useFormCapability(); const formValues = ref<Record<string, string>>({}); let unsubscribeReady: (() => void) | undefined; let unsubscribeChange: (() => void) | undefined; onMounted(() => { const provides = formCapability.value; if (!provides) return; const scope = provides.forDocument(props.documentId); formValues.value = scope.getFormValues(); unsubscribeReady = scope.onFormReady(() => { formValues.value = scope.getFormValues(); }); unsubscribeChange = scope.onFieldValueChange(() => { formValues.value = scope.getFormValues(); }); }); onUnmounted(() => { unsubscribeReady?.(); unsubscribeChange?.(); }); </script>

Set values programmatically

<script setup lang="ts"> import { useFormCapability } from '@embedpdf/plugin-form/vue'; const props = defineProps<{ documentId: string }>(); const { provides: formCapability } = useFormCapability(); const autofill = () => { const scope = formCapability.value?.forDocument(props.documentId); scope?.setFormValues({ First_Name: 'Jane', Last_Name: 'Doe', Email_Address: 'jane.doe@example.com', }); }; </script>

Fill mode vs. design mode

In fill mode, the form category stays locked so widgets remain interactive. In design mode, you unlock annotations so the same widgets can be selected, moved, and resized.

<script setup lang="ts"> import { computed } from 'vue'; import { LockModeType, useAnnotation } from '@embedpdf/plugin-annotation/vue'; const props = defineProps<{ documentId: string }>(); const annotation = useAnnotation(() => props.documentId); const fillModeLock = { type: LockModeType.Include, categories: ['form'], }; const fillMode = computed( () => annotation.state.value.locked.type === LockModeType.Include && annotation.state.value.locked.categories?.includes('form'), ); const toggleMode = () => { annotation.provides.value?.setLocked(fillMode.value ? { type: LockModeType.None } : fillModeLock); }; </script>

Live Example - Switching Between Fill and Design Mode

Live Example - Reading Form State

Live Example - Programmatic Auto Fill

Last updated on March 23, 2026

Need Help?

Join our community for support, discussions, and to contribute to EmbedPDF's development.