npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

svelte-pdf-view

v0.1.13

Published

A modern, modular PDF viewer component for Svelte 5. Built on PDF.js with TypeScript support

Readme

svelte-pdf-view

A modern, modular PDF viewer component for Svelte 5. Built on top of PDF.js, with full TypeScript support and Shadow DOM isolation.

Live Demo

Features

  • PDF Rendering - High-quality PDF rendering powered by PDF.js
  • Text Search - Full-text search with highlight navigation
  • Rotation - Rotate pages clockwise/counter-clockwise
  • Zoom - Zoom in/out controls
  • Responsive - Works on desktop and mobile
  • Customizable - Style the scrollbar, background, and more
  • Modular - Use the default layout or build your own toolbar
  • Shadow DOM - Renderer styles are isolated and won't leak
  • Multiple Sources - Load from URL, ArrayBuffer, Uint8Array, or Blob

Installation

npm install svelte-pdf-view pdfjs-dist
# or
pnpm add svelte-pdf-view pdfjs-dist
# or
yarn add svelte-pdf-view pdfjs-dist

If you want to use the default <PdfToolbar> component, also install:

npm install @lucide/svelte

Vite Configuration

If you're using Vite (including SvelteKit), you may need to exclude pdfjs-dist from dependency optimization to ensure the PDF.js worker loads correctly:

// vite.config.ts
export default defineConfig({
	// ... other config
	optimizeDeps: {
		exclude: ['svelte-pdf-view']
	}
});

This is especially important in monorepo setups where Vite's optimizer may incorrectly bundle the worker.

Quick Start

Basic Usage

<script lang="ts">
	import { PdfViewer, PdfToolbar, PdfRenderer } from 'svelte-pdf-view';
</script>

<div style="height: 100vh;">
	<PdfViewer src="/document.pdf">
		<PdfToolbar />
		<PdfRenderer />
	</PdfViewer>
</div>

The src prop is passed to PdfViewer and automatically shared with PdfRenderer via context - no need to pass it twice!

Loading from Different Sources

<script lang="ts">
	import { PdfViewer, PdfToolbar, PdfRenderer, type PdfSource } from 'svelte-pdf-view';

	// From URL
	let pdfSource: PdfSource = '/document.pdf';

	// From file input
	function handleFileSelect(e: Event) {
		const file = (e.target as HTMLInputElement).files?.[0];
		if (file) {
			pdfSource = file; // Blob works directly
		}
	}

	// From fetch response
	async function loadFromApi() {
		const response = await fetch('/api/document');
		const arrayBuffer = await response.arrayBuffer();
		pdfSource = arrayBuffer;
	}
</script>

<input type="file" accept=".pdf" onchange={handleFileSelect} />

<PdfViewer src={pdfSource}>
	<PdfToolbar />
	<PdfRenderer />
</PdfViewer>

Components

<PdfViewer>

The main container component that provides context for toolbar and renderer.

<PdfViewer src={pdfSource} scale={1.0} class="my-viewer">
	<!-- Children -->
</PdfViewer>

| Prop | Type | Default | Description | | ------------------ | ------------------------- | -------- | ---------------------------------------------------------------------- | | src | PdfSource | required | PDF source (URL, ArrayBuffer, Uint8Array, or Blob) | | scale | number | 1.0 | Initial zoom scale | | downloadFilename | string | - | Custom filename for PDF download (default: from URL or 'document.pdf') | | onerror | (error: string) => void | - | Callback when PDF fails to load | | class | string | '' | CSS class for the container |

Error Handling

<script lang="ts">
	import { PdfViewer, PdfToolbar, PdfRenderer } from 'svelte-pdf-view';

	let errorMessage = $state<string | null>(null);

	function handleError(error: string) {
		errorMessage = error;
		console.error('PDF failed to load:', error);
	}
</script>

{#if errorMessage}
	<div class="error-banner">Failed to load PDF: {errorMessage}</div>
{/if}

<PdfViewer src="/document.pdf" onerror={handleError}>
	<PdfToolbar />
	<PdfRenderer />
</PdfViewer>

<PdfToolbar>

The default toolbar with page navigation, zoom, rotation, and search controls.

<PdfToolbar />

The toolbar automatically connects to the viewer context - no props needed.

<PdfRenderer>

The PDF rendering component. Uses Shadow DOM for style isolation.

<PdfRenderer
	src={pdfSource}
	backgroundColor="#e8e8e8"
	scrollbarThumbColor="#c1c1c1"
	scrollbarTrackColor="#f1f1f1"
	scrollbarThumbHoverColor="#a1a1a1"
	scrollbarWidth="10px"
	pageShadow="0 2px 8px rgba(0, 0, 0, 0.12)"
/>

| Prop | Type | Default | Description | | -------------------------- | ----------- | ----------------------------------- | ------------------------------------ | | src | PdfSource | required | PDF source | | backgroundColor | string | '#e8e8e8' | Background color of scroll container | | pageShadow | string | '0 2px 8px rgba(0,0,0,0.12), ...' | Box shadow for PDF pages | | scrollbarTrackColor | string | '#f1f1f1' | Scrollbar track background | | scrollbarThumbColor | string | '#c1c1c1' | Scrollbar thumb color | | scrollbarThumbHoverColor | string | '#a1a1a1' | Scrollbar thumb hover color | | scrollbarWidth | string | '10px' | Scrollbar width |

Custom Toolbar

You can create your own toolbar using the context API:

<script lang="ts">
	import { PdfViewer, PdfRenderer, getPdfViewerContext } from 'svelte-pdf-view';
</script>

<PdfViewer src="/document.pdf">
	<MyCustomToolbar />
	<PdfRenderer src="/document.pdf" />
</PdfViewer>
<!-- MyCustomToolbar.svelte -->
<script lang="ts">
	import { getPdfViewerContext } from 'svelte-pdf-view';

	const { state, actions } = getPdfViewerContext();
</script>

<div class="toolbar">
	<span>Page {state.currentPage} of {state.totalPages}</span>

	<button onclick={() => actions.zoomOut()}>-</button>
	<span>{Math.round(state.scale * 100)}%</span>
	<button onclick={() => actions.zoomIn()}>+</button>

	<button onclick={() => actions.rotateCounterClockwise()}>↺</button>
	<button onclick={() => actions.rotateClockwise()}>↻</button>
</div>

<style>
	/* Your custom styles */
</style>

Context API

state: PdfViewerState

| Property | Type | Description | | --------------- | ---------------- | ---------------------------------- | | loading | boolean | Whether the PDF is loading | | error | string \| null | Error message if loading failed | | totalPages | number | Total number of pages | | currentPage | number | Current visible page | | scale | number | Current zoom scale | | rotation | number | Current rotation (0, 90, 180, 270) | | searchQuery | string | Current search query | | searchCurrent | number | Current match index | | searchTotal | number | Total number of matches | | isSearching | boolean | Whether search is in progress |

actions: PdfViewerActions

| Method | Description | | ----------------------------- | ---------------------------- | | zoomIn() | Increase zoom level | | zoomOut() | Decrease zoom level | | setScale(scale: number) | Set specific zoom scale | | rotateClockwise() | Rotate 90° clockwise | | rotateCounterClockwise() | Rotate 90° counter-clockwise | | goToPage(page: number) | Navigate to specific page | | search(query: string) | Search for text | | searchNext() | Go to next search match | | searchPrevious() | Go to previous search match | | clearSearch() | Clear search highlights | | download(filename?: string) | Download the PDF |

Types

// PDF source can be URL, ArrayBuffer, Uint8Array, or Blob
type PdfSource = string | ArrayBuffer | Uint8Array | Blob;

interface PdfViewerState {
	loading: boolean;
	error: string | null;
	totalPages: number;
	currentPage: number;
	scale: number;
	rotation: number;
	searchQuery: string;
	searchCurrent: number;
	searchTotal: number;
	isSearching: boolean;
}

interface PdfViewerActions {
	zoomIn: () => void;
	zoomOut: () => void;
	setScale: (scale: number) => void;
	rotateClockwise: () => void;
	rotateCounterClockwise: () => void;
	goToPage: (page: number) => void;
	search: (query: string) => Promise<void>;
	searchNext: () => void;
	searchPrevious: () => void;
	clearSearch: () => void;
	download: (filename?: string) => Promise<void>;
}

Styling Examples

Dark Theme

<PdfRenderer
	src={pdfSource}
	backgroundColor="#1a1a1a"
	scrollbarTrackColor="#2d2d2d"
	scrollbarThumbColor="#555"
	scrollbarThumbHoverColor="#666"
	pageShadow="0 4px 12px rgba(0, 0, 0, 0.5)"
/>

Minimal Theme

<PdfRenderer
	src={pdfSource}
	backgroundColor="#ffffff"
	scrollbarWidth="6px"
	scrollbarTrackColor="transparent"
	scrollbarThumbColor="#ddd"
	pageShadow="none"
/>

Browser Support

  • Chrome/Edge 88+
  • Firefox 78+
  • Safari 14+

License

Apache 2.0

Attribution

This project is built on top of PDF.js by Mozilla, licensed under the Apache License 2.0.

Several files in this project are derivative works based on PDF.js viewer source code:

| File | Based on | | --------------------- | ------------------------------------------------------- | | EventBus.ts | web/event_utils.js | | FindController.ts | web/pdf_find_controller.js, web/text_highlighter.js | | PDFPageView.ts | web/pdf_page_view.js | | PDFViewerCore.ts | web/pdf_viewer.js | | renderer-styles.css | web/text_layer_builder.css |

These files retain the original Apache 2.0 license headers with attribution to the Mozilla Foundation.