PDF Util is a desktop PDF page management app built with Electron, React, and TypeScript. It is designed as a lightweight Acrobat-style workspace focused on page-level manipulation: reordering, extracting, deleting, inserting ranges from another PDF, rotating pages, previewing pages, and exporting a rebuilt PDF.
- User guide: docs/USER_GUIDE.md
- Architecture and diagrams: docs/ARCHITECTURE.md
- Developer guide: docs/DEVELOPER_GUIDE.md
- Troubleshooting: docs/TROUBLESHOOTING.md
Electron + React + TypeScript was chosen over PyQt because the UI requirement is closer to a design-heavy desktop workspace with animated interactions, drag-and-drop, theme switching, and a thumbnail grid that benefits from React's component model and mature frontend tooling. Native dialogs and file access still come from Electron, while PDF rendering and editing are handled in the renderer layer.
- Electron for the desktop shell and native dialogs
- React + TypeScript for the UI
- Zustand for application state and history
- pdf-lib for page editing and export
- PDF.js for thumbnail rendering and page previews
- dnd-kit for drag-and-drop page reordering
The app is split into three clean layers:
electron/: native shell, window bootstrapping, open/save dialogs, and file readssrc/store/: application state, selections, history, undo/redo, and orchestration of page actionssrc/lib/: PDF domain operations such as loading metadata, rendering thumbnails, page deletion, insertion, rotation, and output generationsrc/components/: UI-only React components for the toolbar, sidebar, status bar, thumbnail canvas, and insert dialog
For sequence diagrams, runtime boundaries, and module responsibilities, see docs/ARCHITECTURE.md.
- Open PDF from native file picker
- Drag and drop a PDF into the window
- If a PDF is already open, dropping another PDF lets you replace the current document or add the dropped PDF to the beginning or end
- Thumbnail grid with lazy-loaded previews
- Multi-selection with
Cmd/CtrlandShift - Drag-and-drop page reordering
- Delete selected pages
- Extract selected pages into a new PDF
- Rotate selected pages left or right
- Add every page from another PDF to the beginning or end of the current document
- Insert a single page or page range from another PDF at the beginning, end, or a specific position
- Undo and redo page operations
- Save the rebuilt PDF as a new file
- Dark mode and light mode toggle
- Full-page preview on double-click
- Keyboard shortcuts:
DeleteorBackspacefor deleteCmd/Ctrl+Zfor undoCmd/Ctrl+Shift+ZorCmd/Ctrl+Yfor redoCmd/Ctrl+Sfor save
pdfutil/
├── electron/
│ ├── main.ts
│ └── preload.ts
├── src/
│ ├── components/
│ │ ├── InsertPagesModal.tsx
│ │ ├── Sidebar.tsx
│ │ ├── StatusBar.tsx
│ │ ├── ThumbnailGrid.tsx
│ │ └── Toolbar.tsx
│ ├── lib/
│ │ └── pdf.ts
│ ├── store/
│ │ └── usePdfStore.ts
│ ├── types/
│ │ └── pdf.ts
│ ├── App.tsx
│ ├── main.tsx
│ ├── styles.css
│ └── vite-env.d.ts
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.electron.json
├── vite.config.ts
└── README.md
Prerequisites:
- Node.js 18+
- npm 10+
Install dependencies:
npm installnpm run devThis starts:
- the Vite renderer dev server
- the TypeScript watcher for Electron files
- the Electron desktop app pointed at the dev server
npm run buildThis builds:
- Electron main/preload scripts into
dist-electron/ - the React renderer into
dist/
You can then run the built app shell with:
npm start- Thumbnail rendering is lazy-loaded with
IntersectionObserverto reduce initial work on large PDFs. - Page edits are tracked as page-order snapshots for undo/redo.
- Export always writes a new PDF rather than mutating the source file.
- Current focus is page-level manipulation rather than text/form editing.
electron/main.ts: creates the desktop window and exposes open/save/read handlers through IPC.electron/preload.ts: safely exposes desktop file capabilities to the renderer.src/store/usePdfStore.ts: central state store for the loaded document, selection model, zoom, edit history, and preview state.src/lib/pdf.ts: PDF parsing, thumbnail rendering, output generation, extraction, rotation, reordering, and insertion logic.src/components/ThumbnailGrid.tsx: lazy thumbnail rendering plus sortable drag-and-drop page movement.src/App.tsx: app shell composition, keyboard shortcuts, drag-and-drop document loading, and modal coordination.