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 🙏

© 2026 – Pkg Stats / Ryan Hefner

sv-pdf

v1.1.4

Published

A comprehensive PDF viewer and acceptance component library for Svelte

Readme

sv-pdf

A PDF viewer and acceptance component library for Svelte applications. Built with TypeScript and powered by PDF.js.

Features

  • PDFViewer: Full-featured PDF viewer with zoom, pan, and navigation controls
  • PDFAccept: PDF acceptance component that tracks user progress through document
  • Modular Controls: Override individual control sections (navigation, zoom, actions) with custom snippets
  • Granular Control Disabling: Disable entire control sections OR individual buttons (prev, next, zoom in/out, reset, etc.)
  • Flexible Customization: Customize all button text, labels, and ARIA attributes via props
  • Reset Zoom Modes: Configure reset button behavior (fit to width/height or 100% scale)
  • Zoom Controls: Zoom in/out, auto-fit, and configurable reset functionality
  • Pan & Navigate: Mouse and touch support for panning and navigation
  • Responsive: Mobile-friendly with touch gestures and auto-fit scaling
  • Progress Tracking: Built-in progress indicator for acceptance workflows with auto-completion
  • TypeScript: Full TypeScript support with proper type definitions
  • Accessible: Customizable ARIA labels and keyboard-friendly controls

Installation

npm install sv-pdf pdfjs-dist

Requirements

  • Tailwind CSS: This library uses Tailwind CSS classes. You must have Tailwind CSS configured in your project.
  • PDF.js Worker: Copy pdf.worker.min.mjs from pdfjs-dist/build/ to your static (or public) folder.

If you don't have Tailwind CSS set up yet:

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init

Make sure your tailwind.config.js includes the library's components:

export default {
  content: [
    './src/**/*.{html,js,svelte,ts}',
    './node_modules/sv-pdf/dist/**/*.svelte'
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

Basic Usage

PDFViewer

<script>
  import { PDFViewer } from 'sv-pdf';
</script>

<PDFViewer 
  src="/path/to/document.pdf" 
  width={800} 
  height={600}
/>

PDFAccept

<script>
  import { PDFAccept } from 'sv-pdf';
  
  function handleComplete() {
    console.log('User has accepted the document');
  }
</script>

<PDFAccept 
  src="/path/to/document.pdf" 
  width={800} 
  height={600}
  onComplete={handleComplete}
/>

Component APIs

PDFViewer Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | src | string | - | URL path to PDF file | | base64 | string | - | Base64 encoded PDF data | | width | number \| string | 800 | Viewer width | | height | number \| string | 600 | Viewer height | | autoFitHeight | boolean | false | Auto-fit PDF to container height | | showControls | boolean | true | Show navigation/zoom controls | | controlsPosition | 'top' \| 'bottom' | 'top' | Position of controls | | resetZoomMode | 'width' \| 'height' \| '100%' | 'width' | Reset button zoom behavior | | controls | Snippet<[ControlsProps]> | - | Custom controls snippet (full override) | | navigationControls | Snippet<[ControlsProps]> | - | Custom navigation controls snippet | | zoomControls | Snippet<[ControlsProps]> | - | Custom zoom controls snippet | | actionControls | Snippet<[ControlsProps]> | - | Custom action controls snippet | | disableControls | PDFViewerDisableControls | {} | Selectively disable control sections or individual buttons | | controlsContent | PDFViewerControlsContent | {} | Customize button text and labels | | baseStyling | PDFViewerStyling | {} | Customize component styling with Tailwind classes | | onPageChange | (page: number) => void | - | Callback when page changes | | api | any | - | Bindable API object for programmatic control |

PDFViewerDisableControls Object

{
  // Section-level controls (hides entire section)
  navigation?: boolean;  // Hide entire navigation section
  zoom?: boolean;        // Hide entire zoom section
  actions?: boolean;     // Hide entire actions section
  
  // Granular button-level controls (hide individual buttons)
  prev?: boolean;        // Hide previous page button
  next?: boolean;        // Hide next page button
  zoomIn?: boolean;      // Hide zoom in button
  zoomOut?: boolean;     // Hide zoom out button
  reset?: boolean;       // Hide reset zoom button
  autoFit?: boolean;     // Hide auto-fit button
}

Note: Section-level flags take precedence over button-level flags. For example, if navigation: true, the prev and next flags are ignored since the entire navigation section is hidden.

PDFViewerControlsContent Object

{
  prevButton?: string;      // Default: "Prev"
  nextButton?: string;      // Default: "Next"
  zoomOutButton?: string;   // Default: "−"
  zoomInButton?: string;    // Default: "+"
  autoFitButton?: string;   // Default: "Auto Fit"
  resetButton?: string;     // Default: "Reset"
  loadingText?: string;     // Default: "Loading PDF..."
  errorText?: string;       // Default: "Error: {msg}" (use {msg} for error message)
  ariaLabel?: string;       // Default: "PDF viewer - Use mouse to pan and scroll to zoom"
}

PDFAccept Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | src | string | - | URL path to PDF file | | base64 | string | - | Base64 encoded PDF data | | width | number \| string | 800 | Viewer width | | height | number \| string | 600 | Viewer height | | autoFitHeight | boolean | false | Auto-fit PDF to container height | | showControls | boolean | true | Show navigation/zoom controls | | controlsPosition | 'top' \| 'bottom' | 'bottom' | Position of controls | | resetZoomMode | 'width' \| 'height' \| '100%' | 'width' | Reset button zoom behavior | | controls | Snippet<[AcceptControlsProps]> | - | Custom controls snippet (full override) | | navigationControls | Snippet<[AcceptControlsProps]> | - | Custom navigation controls snippet | | zoomControls | Snippet<[AcceptControlsProps]> | - | Custom zoom controls snippet | | actionControls | Snippet<[AcceptControlsProps]> | - | Custom action controls snippet | | progressIndicator | Snippet<[AcceptControlsProps]> | - | Custom progress indicator snippet | | disableControls | PDFAcceptDisableControls | {} | Selectively disable control sections or individual buttons | | controlsContent | PDFAcceptControlsContent | {} | Customize button text and labels | | baseStyling | PDFAcceptStyling | {} | Customize component styling with Tailwind classes | | onPageChange | (page: number) => void | - | Callback when page changes | | onComplete | () => void | - | Callback when user completes acceptance | | api | any | - | Bindable API object for programmatic control |

PDFAcceptDisableControls Object

{
  // Section-level controls (hides entire section)
  navigation?: boolean;  // Hide entire navigation section
  zoom?: boolean;        // Hide entire zoom section
  actions?: boolean;     // Hide entire actions section
  progress?: boolean;    // Hide progress indicator overlay
  
  // Granular button-level controls (hide individual buttons)
  prev?: boolean;        // Hide previous page button
  next?: boolean;        // Hide next page button
  zoomIn?: boolean;      // Hide zoom in button
  zoomOut?: boolean;     // Hide zoom out button
  reset?: boolean;       // Hide reset zoom button
  done?: boolean;        // Hide done/complete button
}

Note: When done: true, the progress indicator automatically shows "Completed" once the user reaches the last page, since there's no button to click.

PDFAcceptControlsContent Object

{
  prevPage?: string;           // Default: "Prev"
  nextPage?: string;           // Default: "Next"
  prevPageAriaLabel?: string;  // Default: undefined
  nextPageAriaLabel?: string;  // Default: undefined
  pageIndicator?: string;      // Default: "{current} / {total}" (use {current} and {total} placeholders)
  zoomOutButton?: string;      // Default: "−"
  zoomInButton?: string;       // Default: "+"
  resetButton?: string;        // Default: "Reset"
  doneButton?: string;         // Default: "Done"
  completedText?: string;      // Default: "✓ Completed"
  progressText?: string;       // Default: "Progress: {current}/{total}" (use placeholders)
  loadingText?: string;        // Default: "Loading PDF..."
  errorText?: string;          // Default: "Error: {msg}"
  ariaLabel?: string;          // Default: "PDF viewer - Use mouse to pan and scroll to zoom"
}

Advanced Usage

Reset Zoom Modes

Control how the reset button behaves with the resetZoomMode prop:

<script>
  import { PDFViewer } from 'sv-pdf';
</script>

<!-- Reset to fit width (default) -->
<PDFViewer 
  src="/document.pdf"
  resetZoomMode="width"
/>

<!-- Reset to fit height -->
<PDFViewer 
  src="/document.pdf"
  resetZoomMode="height"
/>

<!-- Reset to 100% scale -->
<PDFViewer 
  src="/document.pdf"
  resetZoomMode="100%"
/>

Granular Control Disabling

Disable individual buttons without hiding entire control sections:

<script>
  import { PDFViewer, PDFAccept } from 'sv-pdf';
</script>

<!-- PDFViewer: Hide only the previous button and zoom out -->
<PDFViewer 
  src="/document.pdf"
  disableControls={{ 
    prev: true,
    zoomOut: true 
  }}
/>

<!-- PDFViewer: Hide auto-fit but keep reset -->
<PDFViewer 
  src="/document.pdf"
  disableControls={{ 
    autoFit: true 
  }}
/>

<!-- PDFAccept: Hide done button (auto-completes on last page) -->
<PDFAccept 
  src="/terms.pdf"
  disableControls={{ 
    done: true 
  }}
  onComplete={() => console.log('Auto-completed')}
/>

<!-- PDFAccept: Forward-only navigation (no prev button) -->
<PDFAccept 
  src="/contract.pdf"
  disableControls={{ 
    prev: true 
  }}
/>

<!-- Mix section and button-level disabling -->
<PDFViewer 
  src="/document.pdf"
  disableControls={{ 
    navigation: false,  // Keep navigation section
    prev: true,         // But hide prev button
    actions: false,     // Keep actions section
    autoFit: true       // But hide autoFit button
  }}
/>

Granular Control Behavior:

  • Section-level flags (navigation, zoom, actions) hide entire control groups
  • Button-level flags (prev, next, zoomIn, zoomOut, reset, autoFit, done) hide individual buttons
  • Section-level takes precedence: if navigation: true, individual prev/next flags are ignored
  • PDFAccept auto-completion: When done: true, the progress indicator automatically shows "Completed" when the user reaches the last page

Customizing Text and Labels

<script>
  import { PDFViewer, PDFAccept } from 'sv-pdf';
</script>

<!-- PDFViewer with custom text -->
<PDFViewer 
  src="/document.pdf"
  controlsContent={{
    prevButton: '◀ Previous',
    nextButton: 'Next ▶',
    zoomInButton: '🔍+',
    zoomOutButton: '🔍−',
    resetButton: '↺ Reset View',
    autoFitButton: '⛶ Fit Screen',
    loadingText: 'Loading your document...',
    errorText: 'Failed to load: {msg}'
  }}
/>

<!-- PDFAccept with custom text and placeholders -->
<PDFAccept 
  src="/terms.pdf"
  controlsContent={{
    prevPage: '← Back',
    nextPage: 'Continue →',
    pageIndicator: '{current} of {total}',
    doneButton: 'I Accept',
    completedText: '✅ Accepted',
    progressText: 'Read: {current}/{total} pages',
    prevPageAriaLabel: 'Go to previous page',
    nextPageAriaLabel: 'Go to next page'
  }}
/>

Disabling Specific Controls

<script>
  import { PDFViewer, PDFAccept } from 'sv-pdf';
</script>

<!-- Hide entire zoom section -->
<PDFViewer 
  src="/document.pdf"
  disableControls={{ zoom: true, actions: true }}
/>

<!-- Hide specific buttons only -->
<PDFViewer 
  src="/document.pdf"
  disableControls={{ 
    prev: true,      // Hide previous button
    zoomOut: true,   // Hide zoom out button
    autoFit: true    // Hide auto-fit button
  }}
/>

<!-- PDFAccept: Read-only mode (no done button, auto-completes) -->
<PDFAccept 
  src="/document.pdf"
  disableControls={{ done: true }}
/>

Modular Custom Controls

Override individual control sections while keeping others default:

<script>
  import { PDFViewer } from 'sv-pdf';
</script>

<PDFViewer src="/document.pdf">
  {#snippet navigationControls({ currentPage, totalPages, nextPage, prevPage })}
    <div class="flex gap-2">
      <button onclick={prevPage} class="custom-btn">← Back</button>
      <span class="font-bold">{currentPage} of {totalPages}</span>
      <button onclick={nextPage} class="custom-btn">Forward →</button>
    </div>
  {/snippet}
  <!-- Zoom and action controls remain default -->
</PDFViewer>

PDFAccept with Custom Progress Indicator

<script>
  import { PDFAccept } from 'sv-pdf';
</script>

<PDFAccept 
  src="/terms.pdf"
  controlsContent={{
    doneButton: 'I Accept',
    completedText: '✅ Accepted',
    progressText: 'Read: {current}/{total} pages'
  }}
  onComplete={() => alert('Terms accepted!')}
>
  {#snippet progressIndicator({ isCompleted, maxPageReached, totalPages })}
    <div class="absolute top-2 left-2 px-3 py-1 bg-blue-500 text-white rounded-md">
      {#if isCompleted}
        ✓ Document Accepted
      {:else}
        📖 Pages read: {maxPageReached}/{totalPages}
      {/if}
    </div>
  {/snippet}
</PDFAccept>

Full Custom Controls

<script>
  import { PDFViewer } from 'sv-pdf';
</script>

<PDFViewer src="/document.pdf">
  {#snippet controls({ currentPage, totalPages, zoomIn, zoomOut, nextPage, prevPage })}
    <div class="custom-controls">
      <button onclick={prevPage}>Previous</button>
      <span>{currentPage} / {totalPages}</span>
      <button onclick={nextPage}>Next</button>
      <button onclick={zoomOut}>-</button>
      <button onclick={zoomIn}>+</button>
    </div>
  {/snippet}
</PDFViewer>

Base64 PDF Data

<script>
  import { PDFViewer } from 'sv-pdf';
  
  let base64Data = 'JVBERi0xLjMKJcTl8uXrp/Og0MTGCjQgMCBvYmoKPD...';
</script>

<PDFViewer base64={base64Data} />

Programmatic Control with API Binding

Access the PDF viewer's API to control it programmatically:

<script>
  import { PDFViewer } from 'sv-pdf';
  
  let pdfApi;
  
  function jumpToPage(page: number) {
    pdfApi?.setPage(page);
  }
  
  function handlePageChange(page: number) {
    console.log('Current page:', page);
  }
</script>

<PDFViewer 
  src="/document.pdf"
  bind:api={pdfApi}
  onPageChange={handlePageChange}
/>

<div class="controls">
  <button onclick={() => jumpToPage(1)}>Go to Page 1</button>
  <button onclick={() => pdfApi?.zoomIn()}>Zoom In</button>
  <button onclick={() => pdfApi?.zoomOut()}>Zoom Out</button>
  <button onclick={() => pdfApi?.resetZoom()}>Reset Zoom</button>
  <button onclick={() => pdfApi?.toggleAutoFit()}>Toggle Auto Fit</button>
  
  {#if pdfApi}
    <p>Current Page: {pdfApi.currentPage} / {pdfApi.totalPages}</p>
    <p>Zoom: {Math.round(pdfApi.scale * 100)}%</p>
    <p>Auto Fit: {pdfApi.autoFitEnabled ? 'On' : 'Off'}</p>
  {/if}
</div>

Available API Methods:

  • setPage(page: number): Promise<void> - Navigate to specific page
  • prevPage(): Promise<void> - Go to previous page
  • nextPage(): Promise<void> - Go to next page
  • zoomIn(): Promise<void> - Zoom in
  • zoomOut(): Promise<void> - Zoom out
  • resetZoom(): Promise<void> - Reset zoom (behavior based on resetZoomMode prop)
  • toggleAutoFit(): Promise<void> - Toggle auto-fit mode

Available API Properties (read-only):

  • currentPage: number - Current page number
  • totalPages: number - Total number of pages
  • scale: number - Current zoom scale
  • autoFitEnabled: boolean - Auto-fit mode state
  • isRendering: boolean - Whether currently rendering
  • isLoading: boolean - Whether PDF is loading
  • error: string - Error message if any

TypeScript Support

All types are exported from the package for full type safety:

import { 
  PDFViewer, 
  PDFAccept,
  type PDFViewerProps,
  type PDFAcceptProps,
  type PDFViewerDisableControls,
  type PDFAcceptDisableControls,
  type PDFViewerControlsContent,
  type PDFAcceptControlsContent,
  type ControlsProps,
  type AcceptControlsProps,
  type PDFBaseStyling,
  type PDFViewerStyling,
  type PDFAcceptStyling
} from 'sv-pdf';

// Use types in your code
const viewerControls: PDFViewerDisableControls = {
  prev: true,
  zoomOut: true,
  autoFit: false
};

const acceptContent: PDFAcceptControlsContent = {
  prevPage: 'Back',
  nextPage: 'Continue',
  doneButton: 'I Accept',
  pageIndicator: 'Page {current} of {total}'
};

// Custom snippet with typed props
function MyCustomControls(props: ControlsProps) {
  // props.currentPage, props.totalPages, etc. are all typed
}

Custom Styling with Tailwind CSS

Both PDFViewer and PDFAccept support complete style customization through the baseStyling prop. You can override any element's Tailwind classes while keeping the default styling for elements you don't customize.

How It Works

Each styling property accepts an array of Tailwind class strings. When provided, it completely replaces the default classes for that element:

<script>
  import { PDFViewer, type PDFViewerStyling } from 'sv-pdf';
  
  const customStyling: PDFViewerStyling = {
    // Replace wrapper classes (default is removed, these apply instead)
    wrapper: ['flex', 'flex-col', 'bg-blue-50', 'rounded-xl', 'shadow-2xl'],
    
    // Replace navigation button classes
    navigationButton: ['px-4', 'py-2', 'bg-purple-500', 'text-white', 'rounded-lg'],
    
    // Leave other elements with default styling by not specifying them
  };
</script>

<PDFViewer 
  src="/document.pdf"
  baseStyling={customStyling}
/>

PDFViewerStyling Interface

interface PDFViewerStyling {
  // Inherited from PDFBaseStyling (affects PDF canvas and container)
  container?: string[];        // PDF canvas container
  loadingIndicator?: string[]; // Loading state display
  errorMessage?: string[];     // Error state display
  canvasWrapper?: string[];    // Canvas wrapper with pan transform
  canvas?: string[];           // PDF canvas element
  
  // PDFViewer specific elements
  wrapper?: string[];           // Main component wrapper
  controls?: string[];          // Controls bar container
  navigationSection?: string[]; // Navigation buttons container
  navigationButton?: string[];  // Previous/Next buttons
  pageIndicator?: string[];     // Page counter display
  zoomSection?: string[];       // Zoom controls container
  zoomButton?: string[];        // Zoom in/out buttons
  zoomScale?: string[];         // Zoom percentage display
  actionsSection?: string[];    // Action buttons container
  autoFitButton?: string[];     // Auto-fit toggle button
  resetButton?: string[];       // Reset zoom button
}

Default Classes:

{
  wrapper: ['flex', 'flex-col', 'bg-gray-50', 'rounded-lg', 'shadow-lg', 'overflow-hidden'],
  controls: ['flex', 'items-center', 'justify-between', 'gap-4', 'p-4', 'bg-white', 'border-gray-200'],
  navigationSection: ['flex', 'items-center', 'gap-2', 'flex-shrink-0'],
  navigationButton: ['px-3', 'py-2', 'text-sm', 'font-semibold', 'bg-blue-50', 'text-blue-700', 'rounded-full', 'hover:bg-blue-100', 'disabled:bg-gray-100', 'disabled:text-gray-400', 'disabled:cursor-not-allowed', 'transition-colors'],
  pageIndicator: ['text-sm', 'font-medium', 'text-gray-700', 'text-center', 'bg-gray-50', 'px-3', 'py-2', 'rounded-full', 'whitespace-nowrap'],
  // ... see source code for complete defaults
}

PDFAcceptStyling Interface

interface PDFAcceptStyling extends PDFViewerStyling {
  // All PDFViewerStyling properties plus:
  doneButton?: string[];         // Done/Accept button
  progressIndicator?: string[];  // Progress overlay container
  progressCompleted?: string[];  // Completed state text
}

Additional Defaults:

{
  doneButton: ['px-4', 'py-2', 'text-sm', 'font-semibold', 'bg-emerald-50', 'text-emerald-700', 'rounded-full', 'hover:bg-emerald-100', 'transition-colors', 'border-2', 'border-emerald-200', 'whitespace-nowrap'],
  progressIndicator: ['absolute', 'top-4', 'right-4', 'bg-white/90', 'backdrop-blur-sm', 'rounded-full', 'px-3', 'py-1', 'text-xs', 'font-medium', 'text-gray-600', 'shadow-md'],
  progressCompleted: ['text-emerald-600']
}

Styling Examples

Example 1: Custom Theme Colors

<script>
  import { PDFViewer } from 'sv-pdf';
</script>

<PDFViewer 
  src="/document.pdf"
  baseStyling={{
    wrapper: ['flex', 'flex-col', 'bg-indigo-50', 'rounded-2xl', 'shadow-xl'],
    navigationButton: ['px-4', 'py-2', 'bg-indigo-500', 'text-white', 'rounded-lg', 'hover:bg-indigo-600'],
    zoomButton: ['px-3', 'py-2', 'bg-purple-500', 'text-white', 'rounded-lg', 'hover:bg-purple-600'],
    resetButton: ['px-4', 'py-2', 'bg-gray-600', 'text-white', 'rounded-lg', 'hover:bg-gray-700']
  }}
/>

Example 2: Minimalist Dark Theme

<script>
  import { PDFAccept } from 'sv-pdf';
</script>

<PDFAccept 
  src="/terms.pdf"
  baseStyling={{
    wrapper: ['flex', 'flex-col', 'bg-gray-900', 'rounded-lg'],
    controls: ['flex', 'items-center', 'justify-between', 'p-4', 'bg-gray-800', 'border-t', 'border-gray-700'],
    navigationButton: ['px-3', 'py-2', 'bg-gray-700', 'text-gray-200', 'rounded', 'hover:bg-gray-600'],
    pageIndicator: ['text-gray-300', 'bg-gray-700', 'px-3', 'py-1', 'rounded'],
    zoomButton: ['px-2', 'py-1', 'bg-gray-700', 'text-gray-200', 'rounded', 'hover:bg-gray-600'],
    doneButton: ['px-4', 'py-2', 'bg-green-600', 'text-white', 'rounded', 'hover:bg-green-500'],
    progressIndicator: ['absolute', 'top-4', 'right-4', 'bg-gray-800', 'text-gray-200', 'px-3', 'py-1', 'rounded', 'text-xs'],
    container: ['bg-gray-800'],
    canvas: ['shadow-2xl']
  }}
/>

Example 3: Partial Styling Override

<script>
  import { PDFViewer } from 'sv-pdf';
</script>

<!-- Only customize specific elements, others keep defaults -->
<PDFViewer 
  src="/document.pdf"
  baseStyling={{
    // Custom wrapper
    wrapper: ['flex', 'flex-col', 'bg-gradient-to-br', 'from-blue-50', 'to-purple-50', 'rounded-3xl', 'shadow-2xl', 'p-2'],
    
    // Custom navigation buttons with animations
    navigationButton: ['px-4', 'py-2', 'bg-blue-500', 'text-white', 'rounded-full', 'hover:scale-105', 'transform', 'transition-all', 'duration-200', 'disabled:opacity-50', 'disabled:hover:scale-100'],
    
    // Everything else uses defaults
  }}
/>

Example 4: Compact Mobile-Friendly Styling

<script>
  import { PDFAccept } from 'sv-pdf';
</script>

<PDFAccept 
  src="/contract.pdf"
  baseStyling={{
    controls: ['flex', 'items-center', 'justify-between', 'p-2', 'bg-white', 'border-t', 'text-xs'],
    navigationButton: ['px-2', 'py-1', 'text-xs', 'bg-blue-50', 'text-blue-700', 'rounded'],
    pageIndicator: ['text-xs', 'bg-gray-100', 'px-2', 'py-1', 'rounded'],
    zoomButton: ['px-2', 'py-1', 'text-xs', 'bg-green-50', 'text-green-700', 'rounded'],
    zoomScale: ['text-xs', 'bg-gray-100', 'px-2', 'py-1', 'rounded', 'min-w-[50px]'],
    doneButton: ['px-3', 'py-1', 'text-xs', 'bg-emerald-500', 'text-white', 'rounded'],
    progressIndicator: ['absolute', 'top-2', 'right-2', 'bg-white', 'px-2', 'py-1', 'text-xs', 'rounded', 'shadow']
  }}
/>

Styling Best Practices

  1. Use Tailwind's Design System: Stick to Tailwind's spacing, color, and typography scales for consistency
  2. Consider States: Include hover, disabled, and active states in your custom classes
  3. Responsive Design: Add responsive prefixes (sm:, md:, lg:) for different screen sizes
  4. Accessibility: Maintain sufficient color contrast and interactive element sizing
  5. Transitions: Add transition classes for smooth interactions
  6. Test Thoroughly: Verify your styling works in all component states (loading, error, rendering)

Working with Tailwind JIT

Since the library uses Tailwind classes, make sure your tailwind.config.js includes the library:

export default {
  content: [
    './src/**/*.{html,js,svelte,ts}',
    './node_modules/sv-pdf/dist/**/*.svelte'  // Include library components
  ],
  // ... rest of config
}

Styling

The components use Tailwind CSS classes by default. You can override styles by targeting the component classes or providing your own CSS.

/* Custom styling example */
.pdf-viewer canvas {
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

Requirements

  • Svelte 4.x or 5.x
  • Tailwind CSS 3.x or 4.x
  • PDF.js 4.x or 5.x
  • Modern browser with ES6+ support

Development

# Install dependencies
npm install

# Start development server
npm run dev

# Build package
npm run package

# Run type checking
npm run check

Browser Support

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

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.