Read more about SimplePDF Embed »
Join Our Discord
·
Follow us on Twitter
Easily add SimplePDF to your React app, by using the EmbedPDF component.
npm install @simplepdf/react-embed-pdfThe package root (<EmbedPDF>, useEmbed) has no zod dependency. Only the agentic tools, the opt-in @simplepdf/react-embed-pdf/ai-sdk subpath, need zod (a peer). Install it alongside if you use them (npm 7+ adds it automatically; pnpm / Yarn PnP users must add it explicitly):
npm install zodFor shared product behavior and account-specific features, see the main embed README:
The EmbedPDF component has two modes: "modal" (default) and "inline".
The features below require a SimplePDF account
While the component does not require any account to be used (without any limits), you can specify the companyIdentifier to:
- Automatically collect your users' submissions, configure webhooks, and use BYOS
- Customize branding and white-label behavior
- Use company mode instead of the default mode
Example
import { EmbedPDF } from '@simplepdf/react-embed-pdf';
<EmbedPDF companyIdentifier="yourcompany">
<a href="https://cdn.simplepdf.com/simple-pdf/assets/sample.pdf">Opens sample.pdf</a>
</EmbedPDF>;Modal is the default, just wrap any HTML element and the editor opens in a modal on the user's click. You don't need the mode prop; pass mode="modal" only if you want to be explicit.
import { EmbedPDF } from "@simplepdf/react-embed-pdf";
// Opens the PDF on click
<EmbedPDF>
<a href="https://cdn.simplepdf.com/simple-pdf/assets/sample.pdf">
Opens sample.pdf
</a>
</EmbedPDF>
// Let the user pick the PDF
<EmbedPDF>
<button>Opens the simplePDF editor</button>
</EmbedPDF>Render the PDF editor directly in your app
import { EmbedPDF } from "@simplepdf/react-embed-pdf";
// The PDF is displayed when rendering the component
<EmbedPDF
mode="inline"
style={{ width: 900, height: 800 }}
document={{ url: 'https://cdn.simplepdf.com/simple-pdf/assets/sample.pdf' }}
/>
// The PDF picker is displayed when rendering the component
<EmbedPDF
mode="inline"
style={{ width: 900, height: 800 }}
/>Specify react-viewer as companyIdentifier to disable the editing features:
import { EmbedPDF } from '@simplepdf/react-embed-pdf';
// The PDF is displayed using the viewer: all editing features are disabled
<EmbedPDF
companyIdentifier="react-viewer"
mode="inline"
style={{ width: 900, height: 800 }}
document={{ url: 'https://cdn.simplepdf.com/simple-pdf/assets/sample.pdf' }}
/>;See Data Privacy & companyIdentifier for reserved values and mode behavior.
Some actions require a SimplePDF account. See Retrieving PDF Data for storage and submission behavior.
const { embedRef, actions } = useEmbed(); drives the editor imperatively (actions); the agentic tools come from the opt-in @simplepdf/react-embed-pdf/ai-sdk subpath (useEmbedTools(embedRef)). Attach embedRef to the component: <EmbedPDF ref={embedRef} mode="inline" … />.
Actions are camelCase (the editor's snake_case wire is transformed for you). useEmbed().actions exposes the FULL editor surface; the most common:
| Action | Description |
|---|---|
actions.goTo({ page }) |
Navigate to a specific page |
actions.selectTool({ tool }) |
Select a tool: 'TEXT', 'COMB_TEXT', 'CHECKBOX', 'PICTURE', 'SIGNATURE', or null to deselect |
actions.detectFields() |
Automatically detect form fields in the document |
actions.deleteFields({ fieldIds?, page? }) |
Delete fields by id or page, or all fields if both are omitted |
actions.getDocumentContent({ extractionMode }) |
Extract document content ('auto' or 'ocr') |
actions.setFieldValue({ fieldId, value }) |
Set a field's value |
actions.submit({ downloadCopy }) |
Submit the document |
…plus createField, getFields, focusField, movePage, rotatePage, deletePages, download, and loadDocument. All actions return a Promise with a result object: { success: true, data: ... } or { success: false, error: { code, message } }.
import { EmbedPDF, useEmbed } from '@simplepdf/react-embed-pdf';
const Editor = () => {
const { embedRef, actions } = useEmbed();
const handleSubmit = async () => {
const result = await actions.submit({ downloadCopy: false });
if (result.success) console.log('Submitted!');
};
const handleExtract = async () => {
const result = await actions.getDocumentContent({ extractionMode: 'auto' });
if (result.success) console.log('Pages:', result.data.pages);
};
return (
<>
<button onClick={handleSubmit}>Submit</button>
<button onClick={handleExtract}>Extract Content</button>
<button onClick={() => actions.detectFields()}>Detect Fields</button>
<button onClick={() => actions.selectTool({ tool: 'TEXT' })}>Select Text Tool</button>
<button onClick={() => actions.goTo({ page: 2 })}>Go to Page 2</button>
<EmbedPDF
ref={embedRef}
mode="inline"
companyIdentifier="yourcompany"
style={{ width: 900, height: 800 }}
document={{ url: 'https://cdn.simplepdf.com/simple-pdf/assets/sample.pdf' }}
/>
</>
);
};"Fill and read this document for me" is just these actions in sequence, exactly what an AI agent calls on your behalf (read the fields, fill one, then walk the user to a signature: navigate to its page, focus it, open the signature tool):
const { embedRef, actions } = useEmbed();
const fields = await actions.getFields(); // read
await actions.setFieldValue({ fieldId: 'f_full_name', value: 'Jane Doe' }); // fill
await actions.goTo({ page: 3 });
await actions.focusField({ fieldId: 'f_signature' });
await actions.selectTool({ tool: 'SIGNATURE' });The agentic tools live in the opt-in @simplepdf/react-embed-pdf/ai-sdk subpath, importing it is what pulls zod, so a non-agentic app never loads it (mirroring @simplepdf/embed's /ai-sdk). useEmbedTools(embedRef) binds the SimplePDF tool set to the live editor, drop it straight into the AI SDK and an LLM can drive the editor:
import { useChat } from '@ai-sdk/react';
import { EmbedPDF, useEmbed } from '@simplepdf/react-embed-pdf';
import { useEmbedTools } from '@simplepdf/react-embed-pdf/ai-sdk';
const CopilotEditor = () => {
const { embedRef } = useEmbed();
const tools = useEmbedTools(embedRef);
useChat({ tools }); // the model's tool calls run against the live editor
return <EmbedPDF ref={embedRef} mode="inline" companyIdentifier="yourcompany" style={{ width: 900, height: 800 }} />;
};For server-side tool definitions (execute-less, for streamText), import simplePDFToolDefinitions from the React-free core @simplepdf/embed/ai-sdk (it is intentionally not re-exported from this React subpath, which imports React). embedRef.current is the flat editor-actions handle, every camelCase operation, with the deprecated selectTool / submit overloads; subscribe to editor events via the onEmbedEvent prop. (The framework-free @simplepdf/embed core exposes the grouped embed.actions / embed.events / embed.lifecycle handle for non-React use.)
The TanStack mirror lives in the opt-in @simplepdf/react-embed-pdf/tanstack-ai subpath (importing it pulls @tanstack/ai). useEmbedTools(embedRef) returns the editor-bound client tools; pass them to clientTools(...), then useChat:
import { useChat, clientTools } from '@tanstack/ai-react';
import { EmbedPDF, useEmbed } from '@simplepdf/react-embed-pdf';
import { useEmbedTools } from '@simplepdf/react-embed-pdf/tanstack-ai';
const CopilotEditor = () => {
const { embedRef } = useEmbed();
const tools = clientTools(...useEmbedTools(embedRef));
useChat({ connection, tools }); // the model's tool calls run against the live editor
return <EmbedPDF ref={embedRef} mode="inline" companyIdentifier="yourcompany" style={{ width: 900, height: 800 }} />;
};On your server chat({ tools }) route, register simplePDFToolDefinitions() imported from the React-free core @simplepdf/embed/tanstack-ai (not from this React subpath, which would pull React into your server) so the model is aware of the tools.
See Retrieving PDF Data for text extraction, downloading, and server-side storage options.
| Name | Type | Required | Description |
|---|---|---|---|
| ref | EmbedActions | No | The live editor-actions handle, for programmatic control (see Programmatic Control). Attach the embedRef from useEmbed(). |
| mode | "inline" | "modal" | No (defaults to "modal") | Inline the editor in your layout, or display it inside a click-to-open modal |
| locale | "en" | "de" | "es" | "fr" | "it" | "nl" | "pt" | No (defaults to "en") | Language to display the editor in (ISO locale) |
| children | React.ReactElement | Yes in "modal" mode | Elements triggering the editor |
| companyIdentifier | string | No | Your SimplePDF portal. See Data Privacy & companyIdentifier for reserved values and data handling details. |
| baseDomain | string | No | Override the editor's base domain (defaults to simplepdf.com) |
| context | Record<string, unknown> | No | Sent via webhooks |
| onEmbedEvent | (event: EmbedEvent) => Promise<void> | void |
No | Events sent by the Iframe |
| document | { url: string } | { dataUrl: string } | { file: File | Blob } | No | The document to open (same typed shape as createEmbed): a URL (CORS / authenticated same-origin / a SimplePDF documents URL), a data URL, or a File/Blob |
| style | React.CSSProperties | No | Available for inline mode only |
| className | string | No | Available for inline mode only |
- Link the widget
npm link
npm start- Use it in the target application
npm link @simplepdf/react-embed-pdf