PDF Viewer
PDF viewer with toolbar, page navigation, zoom controls, thumbnail sidebar, search, and annotations.
Basic PDF Viewer
Preview
/ 12
PDF Page Content
<div class="pdf-viewer" style="height: 400px;">
<div class="pdf-viewer-toolbar">
<div class="pdf-viewer-toolbar-group">
<button class="pdf-viewer-btn" aria-label="Previous page">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
</button>
<input class="pdf-viewer-page-input" type="text" value="1"/>
<span class="pdf-viewer-page-total">/ 12</span>
<button class="pdf-viewer-btn" aria-label="Next page">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
</button>
</div>
<div class="pdf-viewer-toolbar-separator"></div>
<div class="pdf-viewer-toolbar-group">
<button class="pdf-viewer-btn" aria-label="Zoom out">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
</button>
<select class="pdf-viewer-zoom-select">
<option>100%</option>
<option>125%</option>
<option>150%</option>
</select>
<button class="pdf-viewer-btn" aria-label="Zoom in">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
</button>
</div>
<div class="pdf-viewer-toolbar-spacer"></div>
<button class="pdf-viewer-btn" aria-label="Download">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
</button>
</div>
<div class="pdf-viewer-container">
<div class="pdf-viewer-page" style="width: 400px; height: 520px; display: flex; align-items: center; justify-content: center;">
<span style="color: var(--color-base-content); opacity: 0.4;">PDF Page Content</span>
</div>
</div>
</div> Requires: ux.min.css
<div class="flex flex-col bg-base-200 rounded-box overflow-hidden" style="height: 400px;">
<div class="flex items-center gap-2 px-4 h-12 bg-base-100 border-b border-base-300 shrink-0">
<button class="inline-flex items-center justify-center w-9 h-9 rounded bg-transparent hover:bg-base-200">...</button>
<input class="w-12 h-8 text-center text-sm border border-base-300 rounded" value="1"/>
<span class="text-sm text-base-content/60">/ 12</span>
</div>
<div class="flex-1 overflow-auto flex flex-col items-center gap-4 p-6">
<div class="bg-base-100 shadow" style="width: 400px; height: 520px;">PDF Page</div>
</div>
</div> Requires: tw.min.css
// Use pdf.js to render pages:
// const pdf = await pdfjsLib.getDocument(url).promise;
// const page = await pdf.getPage(pageNum);
// const viewport = page.getViewport({ scale });
// const canvas = document.querySelector('.pdf-viewer-page canvas');
// await page.render({ canvasContext: canvas.getContext('2d'), viewport }).promise; With Thumbnails
Preview
1
2
3
/ 3
Page 1
<div class="pdf-viewer pdf-viewer-with-thumbnails" style="height: 400px;">
<div class="pdf-viewer-thumbnails">
<div class="pdf-viewer-thumbnail pdf-viewer-thumbnail-active">
<div style="width: 100%; height: 80px; background: var(--color-base-200);"></div>
<div class="pdf-viewer-thumbnail-label">1</div>
</div>
<div class="pdf-viewer-thumbnail">
<div style="width: 100%; height: 80px; background: var(--color-base-200);"></div>
<div class="pdf-viewer-thumbnail-label">2</div>
</div>
<div class="pdf-viewer-thumbnail">
<div style="width: 100%; height: 80px; background: var(--color-base-200);"></div>
<div class="pdf-viewer-thumbnail-label">3</div>
</div>
</div>
<div class="pdf-viewer-main">
<div class="pdf-viewer-toolbar">
<div class="pdf-viewer-toolbar-group">
<button class="pdf-viewer-btn" aria-label="Previous">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
</button>
<input class="pdf-viewer-page-input" type="text" value="1"/>
<span class="pdf-viewer-page-total">/ 3</span>
<button class="pdf-viewer-btn" aria-label="Next">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
</button>
</div>
<div class="pdf-viewer-toolbar-spacer"></div>
</div>
<div class="pdf-viewer-container">
<div class="pdf-viewer-page" style="width: 350px; height: 460px; display: flex; align-items: center; justify-content: center;">
<span style="color: var(--color-base-content); opacity: 0.4;">Page 1</span>
</div>
</div>
</div>
</div> Requires: ux.min.css
<div class="flex bg-base-200 rounded-xl overflow-hidden" style="height: 400px;">
<div class="flex flex-col gap-2 shrink-0 overflow-y-auto p-2 bg-base-100 border-r border-base-300" style="width: 160px;">
<div class="cursor-pointer rounded p-1 border-2 border-primary">
<div class="w-full bg-base-200" style="height: 80px;"></div>
<div class="text-xs text-center text-base-content/60 mt-1">1</div>
</div>
<div class="cursor-pointer rounded p-1 border-2 border-transparent hover:border-base-300">
<div class="w-full bg-base-200" style="height: 80px;"></div>
<div class="text-xs text-center text-base-content/60 mt-1">2</div>
</div>
<div class="cursor-pointer rounded p-1 border-2 border-transparent hover:border-base-300">
<div class="w-full bg-base-200" style="height: 80px;"></div>
<div class="text-xs text-center text-base-content/60 mt-1">3</div>
</div>
</div>
<div class="flex flex-col flex-1 min-w-0">
<div class="flex items-center gap-2 px-4 h-12 bg-base-100 border-b border-base-300 shrink-0">
<button class="inline-flex items-center justify-center w-9 h-9 rounded bg-transparent hover:bg-base-200 border-none cursor-pointer text-base-content">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg>
</button>
<input class="w-12 h-8 text-center text-sm border border-base-300 rounded bg-base-100 text-base-content" value="1"/>
<span class="text-sm text-base-content/60">/ 3</span>
<button class="inline-flex items-center justify-center w-9 h-9 rounded bg-transparent hover:bg-base-200 border-none cursor-pointer text-base-content">
<svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
</button>
<div class="flex-1"></div>
</div>
<div class="flex-1 overflow-auto flex flex-col items-center gap-4 p-6">
<div class="bg-base-100 shadow flex items-center justify-center" style="width: 350px; height: 460px;">
<span class="text-base-content/40">Page 1</span>
</div>
</div>
</div>
</div> Requires: tw.min.css
// Click thumbnail to navigate to page:
// thumbnail.addEventListener('click', () => renderPage(pageNum)); Loading & Error States
Preview
Loading document...
Failed to load PDF
<div class="flex gap-4">
<!-- Loading -->
<div class="pdf-viewer" style="height: 250px; width: 300px;">
<div class="pdf-viewer-loading">
<div class="pdf-viewer-loading-spinner"></div>
<div class="pdf-viewer-loading-text">Loading document...</div>
</div>
</div>
<!-- Error -->
<div class="pdf-viewer" style="height: 250px; width: 300px;">
<div class="pdf-viewer-error">
<svg class="pdf-viewer-error-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
<div class="pdf-viewer-error-text">Failed to load PDF</div>
</div>
</div>
</div> Requires: ux.min.css
<div class="flex gap-4">
<!-- Loading -->
<div class="relative flex flex-col bg-base-200 rounded-xl overflow-hidden" style="height: 250px; width: 300px;">
<div class="absolute inset-0 flex flex-col items-center justify-center gap-4 bg-base-200">
<div class="w-10 h-10 rounded-full border-3 border-base-300 border-t-primary animate-spin"></div>
<span class="text-sm text-base-content/60">Loading document...</span>
</div>
</div>
<!-- Error -->
<div class="relative flex flex-col bg-base-200 rounded-xl overflow-hidden" style="height: 250px; width: 300px;">
<div class="absolute inset-0 flex flex-col items-center justify-center gap-4 bg-base-200 text-center p-8">
<svg class="w-12 h-12 text-error" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>
<span class="text-base-content">Failed to load PDF</span>
</div>
</div>
</div> Requires: tw.min.css
// Show loading state, then swap to content or error:
// try { await renderPdf(url); } catch(e) { showError(); }