pdf-flipper
v1.0.0
Published
A responsive, animated PDF flipbook viewer. Give it a PDF URL and watch it turn into a beautiful interactive book.
Maintainers
Readme
pdf-flipbook
A responsive, animated PDF flipbook viewer.
Give it a PDF URL and it becomes a beautiful interactive book — complete with page-turn animations, keyboard/swipe navigation, and full responsiveness.
✨ Features
- 📖 Realistic 3D page-flip animation (CSS transforms, no WebGL needed)
- 📄 Renders any PDF via PDF.js — no server required
- 📱 Fully responsive — two-page spread on desktop, single page on mobile
- ⌨️ Keyboard navigation (← →) and touch swipe support
- 🎨 Dark & light themes built-in, fully customisable via CSS variables
- 🧩 Works with React, Vue, vanilla JS, or any framework
- 🌐 No jQuery, no heavy UI libraries
📦 Installation
npm install pdf-flipbook
# or
yarn add pdf-flipbook🚀 Quick Start
1 — Vanilla JS (ESM)
<div id="my-book" style="height: 600px;"></div>
<script type="module">
import PdfFlipbook from 'pdf-flipbook';
import 'pdf-flipbook/style.css';
const book = new PdfFlipbook('#my-book', 'https://example.com/document.pdf');
</script>2 — Vanilla JS (UMD / CDN)
<link rel="stylesheet" href="https://unpkg.com/pdf-flipbook/dist/pdf-flipbook.css">
<script src="https://unpkg.com/pdf-flipbook/dist/pdf-flipbook.umd.js"></script>
<div id="my-book"></div>
<script>
const { PdfFlipbook } = window.PdfFlipbook;
new PdfFlipbook('#my-book', '/path/to/file.pdf');
</script>3 — React
import { useEffect, useRef } from 'react';
import PdfFlipbook from 'pdf-flipbook';
import 'pdf-flipbook/style.css';
export default function BookViewer({ pdfUrl }) {
const ref = useRef(null);
useEffect(() => {
if (!ref.current) return;
const book = new PdfFlipbook(ref.current, pdfUrl, { theme: 'light' });
return () => book.destroy();
}, [pdfUrl]);
return <div ref={ref} style={{ height: 600 }} />;
}4 — Vue 3
<template>
<div ref="container" style="height: 600px" />
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import PdfFlipbook from 'pdf-flipbook';
import 'pdf-flipbook/style.css';
const props = defineProps({ pdfUrl: String });
const container = ref(null);
let book;
onMounted(() => {
book = new PdfFlipbook(container.value, props.pdfUrl);
});
onUnmounted(() => book?.destroy());
</script>⚙️ API
new PdfFlipbook(container, pdfUrl, options?)
| Parameter | Type | Description |
|-------------|---------------------------|--------------------------------------------|
| container | string \| HTMLElement | CSS selector or DOM element to mount into |
| pdfUrl | string | URL of the PDF to display |
| options | object | Optional configuration (see below) |
Options
| Option | Type | Default | Description |
|--------------------|------------|-----------|----------------------------------------------------|
| flipDuration | number | 700 | Page-flip animation duration (ms) |
| shadowIntensity | number | 0.4 | Shadow opacity at peak flip (0–1) |
| maxDpr | number | 2 | Max device-pixel-ratio for canvas quality |
| toolbar | boolean | true | Show the bottom toolbar with page info |
| theme | string | "dark" | "dark" or "light" |
| preloadAhead | number | 2 | Pages to preload ahead of current spread |
| onFlip | function | null | Callback: (fromPage, toPage) => void |
| onReady | function | null | Callback: () => void — all pages loaded |
| onError | function | null | Callback: (error) => void |
Instance Methods
book.next() // Turn to the next spread
book.prev() // Turn to the previous spread
book.goTo(pageNum) // Jump to a specific page (1-indexed)
book.destroy() // Remove the flipbook and clean up eventsStatic Properties
// Override the PDF.js worker URL (do this before instantiating):
PdfFlipbook.workerSrc = '/path/to/pdf.worker.min.mjs';🎨 Theming
The flipbook is fully customisable via CSS variables on the .pfb element:
.pfb {
--pfb-bg: #1a1a2e; /* stage background */
--pfb-page-bg: #fdfaf5; /* page background colour */
--pfb-spine-color: #0f0f1a; /* spine colour */
--pfb-spine-width: 12px; /* spine width */
--pfb-accent: #c9a96e; /* loader/accent colour */
--pfb-flip-z: 600px; /* perspective depth */
--pfb-book-shadow: 0 30px 80px rgba(0,0,0,.6);
}🌍 CORS & PDF Sources
PDF.js fetches the file from the browser, so the PDF server must serve the correct CORS headers:
Access-Control-Allow-Origin: *If you control the server, add that header. If you're loading local files during development, serve them via a local HTTP server (not file://).
📋 Browser Support
| Browser | Support | |---------|---------| | Chrome 90+ | ✅ | | Firefox 88+ | ✅ | | Safari 14+ | ✅ | | Edge 90+ | ✅ | | IE 11 | ❌ |
📝 License
MIT © 2024
