@equitylist-co/pdf-editor
v1.0.33
Published
A modern, aesthetic React-based PDF annotation application that allows users to intuitively drag and drop placeholder fields onto PDF documents. Features a sleek interface with full-screen PDF viewing, precise coordinate tracking, and advanced field manag
Downloads
88
Maintainers
Readme
PDF Annotation Studio
A modern, aesthetic React-based PDF annotation application that allows users to intuitively drag and drop placeholder fields onto PDF documents. Features a sleek interface with full-screen PDF viewing, precise coordinate tracking, and advanced field management capabilities.
Features
- 📄 PDF Rendering: Display PDF documents using react-pdf
- 🎯 Drag & Drop: Intuitive drag-and-drop interface for placing annotation fields
- 📐 Coordinate Capture: Precise coordinate tracking as percentages (0-1) relative to page dimensions
- 🔄 Field Management: Move, resize, and delete annotation fields
- 👁️ Preview Mode: View-only mode to display saved annotations
- 🎨 Modern UI: Clean Tailwind CSS styling with responsive design
- 📱 Zoom Control: Adjustable zoom levels for precise field placement
- 📝 Text Fields: Editable text areas for custom content input
- 🖼️ Image Fields: File picker integration for image placement
- 👥 Assignee Selection: Multi-user assignment for signature, initials, name, and title fields
- 🔄 Smart Duplication: Automatic field duplication for multiple assignees
Components
PdfAnnotatorCreate
Interactive component for creating and editing PDF annotations with drag-and-drop functionality.
Props:
fileUrl: PDF file URLplaceholderTypes: Array of placeholder type configurations with icons and assignee optionsinitialFields?: Optional array of existing fields for editingonSave: Callback function when saving fields
PlaceholderType Configuration:
{
value: string; // Field type identifier (e.g., "signature", "text", "image")
label: string; // Display name (e.g., "Signature", "Text Field", "Image")
icon: () => React.ReactNode; // Icon component for the sidebar
assigneeOptions?: { // Optional user assignment for multi-user fields
name: string;
id: string;
}[];
}Features:
- Drag & Drop Interface: Drag placeholder types from sidebar onto PDF pages
- Field Management: Click and drag to reposition fields, resize using corner handles
- Field Types: Support for text fields, image fields, and assignee-based fields
- Multi-User Assignment: Fields with assignee options automatically duplicate for multiple users
- Interactive Editing:
- Text fields: Direct text input with real-time updates
- Image fields: File picker integration for image uploads
- Assignee fields: Dropdown selection for user assignment
- Visual Controls: Delete fields with × button, zoom control for precise placement
- Smart Positioning: Automatic field positioning when multiple assignees are selected
PdfAnnotatorDisplay
Read-only component for viewing PDF documents with saved annotations and interactive navigation.
Props:
fileUrl: PDF file URLfields: Array of Field objects to displayshowSidebar?: Optional boolean to show/hide the sidebar (default: true)
Features:
- PDF Rendering: Display PDF with overlay annotations using react-pdf
- Interactive Sidebar: Field summary with statistics and detailed field list
- Field Navigation: Clickable field items that scroll to and highlight fields on the PDF
- Zoom Control: Adjustable zoom levels with smooth scaling
- Field Statistics: Automatic grouping and counting of fields by type
- Programmatic Control: External control via useImperativeHandle for programmatic field navigation
- Visual Feedback: Temporary field highlighting with smooth animations
Ref Methods:
scrollToField(fieldId: string): Smoothly scrolls to a specific field and centers ithighlightField(fieldId: string): Highlights a field temporarily (2-second duration)
Data Model
Field Type
type Field = {
page: number; // 1-based page number
type: string; // placeholder type (e.g., "signature", "text", "image")
x: number; // left position (0–1, relative to width)
y: number; // top position (0–1, relative to height)
width: number; // width (0–1, relative to width)
height: number; // height (0–1, relative to height)
metadata?: { // optional field-specific data
textValue?: string; // for text fields
imageUrl?: string; // for image fields
assignedUserIds?: string[]; // for assignee-based fields
[key: string]: any; // additional custom metadata
};
id: string; // unique identifier for the field
};DragItem Type
interface DragItem {
type: string; // drag item type
fieldType: string; // field type being dragged
isNew?: boolean; // true for new fields from sidebar
fieldIndex?: number; // index for existing field repositioning
field?: Field; // field data for existing fields
}Installation
- Install dependencies:
yarn install- Start the development server:
yarn devUsage
Basic Example
import PdfAnnotatorCreate from './components/PdfAnnotatorCreate';
import PdfAnnotatorDisplay, { type PdfAnnotatorDisplayRef } from './components/PdfAnnotatorDisplay';
import { Field } from './types/Field';
import { useRef, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
function App() {
const [fields, setFields] = useState<Field[]>([]);
const [showSidebar, setShowSidebar] = useState(true);
const pdfDisplayRef = useRef<PdfAnnotatorDisplayRef>(null);
// Configure placeholder types with icons and assignee options
const placeholderTypes = [
{
value: 'signature',
label: 'Signature',
icon: () => <span>✍️</span>,
assigneeOptions: [
{ name: 'John Doe', id: 'user1' },
{ name: 'Jane Smith', id: 'user2' }
]
},
{
value: 'text',
label: 'Text Field',
icon: () => <span>📝</span>
},
{
value: 'image',
label: 'Image',
icon: () => <span>🖼️</span>
},
{
value: 'date',
label: 'Date',
icon: () => <span>📅</span>
}
];
const pdfUrl = 'path/to/your/document.pdf';
const handleSave = (newFields: Field[]) => {
const fieldsWithIds = newFields.map((field) => ({
...field,
id: field.id || uuidv4()
}));
setFields(fieldsWithIds);
};
const scrollToFirstField = () => {
if (fields.length > 0 && pdfDisplayRef.current) {
pdfDisplayRef.current.scrollToField(fields[0].id);
pdfDisplayRef.current.highlightField(fields[0].id);
}
};
return (
<div>
<PdfAnnotatorCreate
fileUrl={pdfUrl}
placeholderTypes={placeholderTypes}
initialFields={fields}
onSave={handleSave}
/>
<div>
<button onClick={() => setShowSidebar(!showSidebar)}>
{showSidebar ? 'Hide Sidebar' : 'Show Sidebar'}
</button>
<button onClick={scrollToFirstField}>
Scroll to First Field
</button>
<PdfAnnotatorDisplay
ref={pdfDisplayRef}
fileUrl={pdfUrl}
fields={fields}
showSidebar={showSidebar}
/>
</div>
</div>
);
}Advanced Features
Multi-User Field Assignment
Fields with assignee options automatically duplicate when multiple users are selected:
const placeholderTypes = [
{
value: 'signature',
label: 'Signature',
icon: () => <span>✍️</span>,
assigneeOptions: [
{ name: 'John Doe', id: 'user1' },
{ name: 'Jane Smith', id: 'user2' },
{ name: 'Bob Johnson', id: 'user3' }
]
}
];
// When a user selects multiple assignees, the system automatically:
// 1. Creates separate fields for each assignee
// 2. Positions them vertically below the original field
// 3. Each field contains only one assigned user IDField Types and Metadata
Different field types support specific metadata:
// Text fields store user input
{
type: 'text',
metadata: {
textValue: 'User entered text here'
}
}
// Image fields store file URLs
{
type: 'image',
metadata: {
imageUrl: '/path/to/uploaded/image.jpg'
}
}
// Assignee fields store user assignments
{
type: 'signature',
metadata: {
assignedUserIds: ['user1', 'user2']
}
}Hiding the Sidebar
You can display only the PDF without the sidebar by setting showSidebar={false}:
<PdfAnnotatorDisplay
fileUrl={pdfUrl}
fields={fields}
showSidebar={false}
/>Programmatic Field Navigation
Use the ref to programmatically scroll to and highlight fields:
const pdfDisplayRef = useRef<PdfAnnotatorDisplayRef>(null);
// Scroll to a specific field
pdfDisplayRef.current?.scrollToField('550e8400-e29b-41d4-a716-446655440000');
// Highlight a field temporarily
pdfDisplayRef.current?.highlightField('550e8400-e29b-41d4-a716-446655440000');
// Combined: scroll and highlight
pdfDisplayRef.current?.scrollToField('550e8400-e29b-41d4-a716-446655440000');
pdfDisplayRef.current?.highlightField('550e8400-e29b-41d4-a716-446655440000');Interactive Field Management
- Drag & Drop: Drag fields from sidebar to create new annotations
- Repositioning: Click and drag existing fields to move them
- Resizing: Use corner handles to resize fields
- Deletion: Click the × button to remove fields
- Real-time Updates: Text and image fields update immediately as you type or upload
Coordinate System
The coordinate system uses percentages (0-1) relative to the PDF page dimensions:
x: 0= left edge of pagex: 1= right edge of pagey: 0= top edge of pagey: 1= bottom edge of page
This ensures annotations maintain their relative positions across different zoom levels and screen sizes.
Technologies Used
- React 19 with TypeScript
- react-pdf for PDF rendering and document management
- react-dnd for drag-and-drop functionality with HTML5 backend
- Radix UI for accessible dropdown menus and UI components
- Tailwind CSS for styling with scoped library classes
- Vite for build tooling and development server
- UUID for unique field identification
Browser Support
- Modern browsers with ES6+ support
- PDF.js worker for cross-browser PDF rendering
Steps to deploy library
- Run
publish.shscript to deploy to npm.
License
MIT License
