# Angular PDF viewer powered by Mozilla's PDF.js

The most reliable, feature-rich Angular PDF viewer component powered by Mozilla's PDF.js

<div align="center">
<img src="https://raw.githubusercontent.com/intbot/ng2-pdfjs-viewer/master/lib/logo.svg" alt="ng2-pdfjs-viewer Logo" width="120" height="140" />
</div>

<div align="center">

[![NPM Version](https://img.shields.io/npm/v/ng2-pdfjs-viewer?logo=npm&color=blue)](https://www.npmjs.com/package/ng2-pdfjs-viewer)
[![PDF.js Version](https://img.shields.io/badge/PDF.js%20v5.3.93-latest-green?logo=mozilla)](https://github.com/mozilla/pdf.js)
[![Angular Support](https://img.shields.io/badge/Angular%2020+-supported-red?logo=angular)](https://angular.dev/overview)
[![NPM Downloads](https://img.shields.io/npm/dm/ng2-pdfjs-viewer?label=downloads%2Fmonth&color=orange)](https://www.npmjs.com/package/ng2-pdfjs-viewer)
[![Total Downloads](https://img.shields.io/badge/total%20downloads-7M+-brightgreen?logo=npm)](https://www.npmjs.com/package/ng2-pdfjs-viewer)
[![Since 2018](https://img.shields.io/badge/since-2018-blue?logo=calendar)](https://www.npmjs.com/package/ng2-pdfjs-viewer)
[![License](https://img.shields.io/badge/license-Apache%202.0%20%2B%20Commons%20Clause-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
[![GitHub Stars](https://img.shields.io/github/stars/intbot/ng2-pdfjs-viewer?logo=github)](https://github.com/intbot/ng2-pdfjs-viewer)

</div>

<div align="center">

[**Live Demo**](https://angular-pdf-viewer-demo.vercel.app/) • [**Documentation**](https://angular-pdf-viewer-docs.vercel.app/) • [**API Reference**](#-api-reference) • [**Examples**](#-examples) • [**Server Examples**](../Server-Side-Examples.md) • [**Migration Guide**](#-migration-guide)

</div>

---

ng2-pdfjs-viewer is the most comprehensive and feature-rich Angular PDF viewer component available. **Born in 2018** and still going strong with over **7+ million downloads**, this battle-tested library has been trusted by developers worldwide for **over 8 years**, powering thousands of applications.

This powerful library enables developers to seamlessly integrate PDF viewing capabilities into Angular applications with enterprise-grade features, custom theming, and mobile-first responsive design. Built on Mozilla's PDF.js v5.3.93, ng2-pdfjs-viewer provides advanced PDF rendering, document navigation, search functionality, and extensive customization options.

Whether you need a simple embedded PDF viewer or a complex document management system, this component delivers the performance and flexibility required for modern Angular applications. **The most mature and reliable Angular PDF viewer solution** with continuous updates and long-term support.

### Why Choose ng2-pdfjs-viewer?

- **🚀 Always Up-to-Date** - Continuously updated with the latest PDF.js versions and Angular compatibility
- **🏗️ Enterprise-Ready** - Built for production with comprehensive error handling and performance optimization
- **🎨 Highly Customizable** - Extensive theming options, custom templates, and flexible configuration
- **📱 Mobile Optimized** - Touch-friendly interface with responsive design for all screen sizes
- **🔧 Developer Friendly** - Full TypeScript support, comprehensive documentation, and easy integration
- **⚡ High Performance** - Event-driven architecture with efficient memory management and lazy loading
- **🌍 Global Support** - Multi-language support with automatic locale detection and RTL compatibility
- **🛡️ Production Tested** - Trusted by thousands of applications with millions of downloads
- **📈 Proven Track Record** - 8+ years of continuous development and community support
- **🔒 Security Focused** - Regular security updates and vulnerability patches

### 🆕 Latest Features (v25.x)

| Feature                       | Description                                                        | Status |
| ----------------------------- | ------------------------------------------------------------------ | ------ |
| **Advanced Theme System**     | CSS custom properties for complete visual customization            | ✅ New |
| **Template-Based UI**         | Custom loading spinners and error displays using Angular templates | ✅ New |
| **Convenience Configuration** | Object-based configuration for cleaner, more maintainable code     | ✅ New |
| **Event-Driven Architecture** | Pure event-based system with universal action dispatcher           | ✅ New |
| **Enhanced Error Handling**   | Multiple error display styles with custom templates                | ✅ New |
| **Mobile-First Design**       | Responsive layout optimized for touch devices                      | ✅ New |
| **TypeScript Strict Mode**    | Full type safety with comprehensive API coverage                   | ✅ New |
| **URL Security Validation**   | Prevents unauthorized file parameter manipulation with custom templates | ✅ New |

### 🏆 Unique Advantages

- **Universal Action Dispatcher** - Single pathway for all actions with readiness validation
- **Template-Based Customization** - Use Angular templates for loading and error states
- **Comprehensive Event System** - 24+ events covering all user interactions and state changes
- **Advanced Configuration Objects** - Clean, object-based configuration for complex setups
- **Production-Ready Architecture** - Event-driven design with no timeouts or polling
- **Complete API Coverage** - 19+ methods with consistent Promise-based returns

### 🎯 Perfect For

- **Enterprise Applications** - Robust, scalable PDF viewing for business applications
- **Document Management Systems** - Complete PDF handling with search and navigation
- **E-Learning Platforms** - Interactive PDF viewing for educational content
- **Financial Applications** - Secure PDF viewing for reports and statements
- **Healthcare Systems** - Reliable PDF viewing for medical documents
- **Government Portals** - Accessible PDF viewing for public services
- **E-Commerce Platforms** - Product catalogs and documentation viewing
- **Content Management Systems** - Integrated PDF viewing and management

---

## 📋 Table of Contents

- [Quick Start](#-quick-start)
- [Features](#-features)
- [Installation](#-installation)
- [Basic Usage](#-basic-usage)
- [Advanced Configuration](#advanced-configuration)
- [API Reference](#-api-reference)
- [Examples](#-examples)
- [Migration Guide](#-migration-guide)
- [Deprecated Features](#deprecated-features)
- [Contributing](#-contributing)
- [License](#-license)

---

## 🚀 Quick Start

> **🎯 Live Demo**: [https://angular-pdf-viewer-demo.vercel.app/](https://angular-pdf-viewer-demo.vercel.app/)  
> **📚 Documentation**: [https://angular-pdf-viewer-docs.vercel.app/](https://angular-pdf-viewer-docs.vercel.app/)  
> **📁 Source Code**: [https://github.com/intbot/ng2-pdfjs-viewer/tree/main/SampleApp](https://github.com/intbot/ng2-pdfjs-viewer/tree/main/SampleApp)

### 1. Install the Package

```bash
npm install ng2-pdfjs-viewer --save
```

### 2. Import the Module

```typescript
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { PdfJsViewerModule } from "ng2-pdfjs-viewer";

@NgModule({
  imports: [BrowserModule, PdfJsViewerModule],
  // ... rest of your module
})
export class AppModule {}
```

### 3. Use in Your Component

```html
<ng2-pdfjs-viewer
  pdfSrc="assets/sample.pdf"
  [showSpinner]="true"
  [theme]="'light'"
>
</ng2-pdfjs-viewer>
```

### 4. Configure Assets (Required)

Add PDF.js assets to your `angular.json`:

```json
{
  "projects": {
    "your-app": {
      "architect": {
        "build": {
          "options": {
"assets": [
              {
                "glob": "**/*",
                "input": "node_modules/ng2-pdfjs-viewer/pdfjs",
                "output": "/assets/pdfjs"
              }
            ]
          }
        }
      }
    }
  }
}
```

---

## ✨ Features

**🎉 7+ Million Downloads & Counting!** - Trusted by developers worldwide for reliable PDF viewing in Angular applications since 2018.

### 🎯 Core PDF Viewing Features

- **📄 High-Quality PDF Rendering** - Powered by Mozilla's PDF.js v5.3.93 for superior document display
- **🔄 Multiple Display Modes** - Embedded viewer, new window, or external tab options
- **📱 Mobile-First Responsive Design** - Touch-friendly controls optimized for all devices
- **🌍 Complete Internationalization** - Support for 50+ languages with automatic locale detection
- **⚡ Optimized Performance** - Lazy loading, memory management, and efficient rendering

### 🎨 Visual Customization

- **🎨 Theme System** - Light, dark, and auto themes with custom color schemes
- **🎭 Custom Styling** - CSS custom properties for complete visual control
- **🔄 Loading States** - Custom loading spinners with template support
- **❌ Error Handling** - Multiple error display styles with custom templates
- **📐 Layout Control** - Toolbar density, sidebar width, and positioning options

### 🔧 Developer Features

- **📝 TypeScript Support** - Full type safety with strict mode
- **🔌 Event System** - Comprehensive event handling for all user interactions
- **⚙️ Configuration Objects** - Convenience setters for cleaner code
- **🛠️ API Methods** - Promise-based methods for programmatic control
- **🐛 Debugging** - Built-in diagnostic logging and error tracking

### 📊 Advanced Features

- **🔍 Search & Navigation** - Full-text search with highlighting
- **📖 Bookmarks & Attachments** - Document structure navigation
- **🖨️ Print & Download** - Built-in print and download functionality
- **🔄 Rotation & Zoom** - Document manipulation with smooth animations
- **📱 Touch Gestures** - Mobile-optimized touch interactions

### 🔒 Security Features

- **CSP Compliant** - Works with strict Content Security Policy (`style-src 'self'`)
- **URL Validation** - Prevents unauthorized file parameter manipulation in external viewer
- **Custom Security Templates** - Angular template support for security warnings
- **Console Warnings** - Developer-friendly security notifications

---

## 📦 Installation

### Prerequisites

- **Angular**: 20.0+ (recommended) | 2.0+ (supported)
- **Node.js**: 18.0+
- **TypeScript**: 5.0+

### Production Deployment

#### Nginx Configuration

For production deployments using nginx, configure MIME types for PDF.js ES modules:

```nginx
# Add to your nginx.conf or site configuration
types {
    application/javascript  js mjs;
    text/plain             ftl;
}
```

#### IIS Configuration (Windows Server)

For production deployments using IIS, add to your `web.config`:

```xml
<configuration>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".mjs" mimeType="application/javascript" />
      <mimeMap fileExtension=".ftl" mimeType="text/plain" />
    </staticContent>
  </system.webServer>
</configuration>
```

**Why this is needed**: PDF.js v5+ uses `.mjs` files (ES modules) and `.ftl` files (localization). Without proper MIME type configuration, web servers serve these files with incorrect content-type headers, causing the PDF viewer to crash during loading in production environments.

### Angular Version Support

| Angular Version | Support Level | Notes |
|----------------|---------------|-------|
| **20.0+** | ✅ **Recommended** | Fully tested and optimized |
| **15.0 - 19.x** | ✅ **Supported** | Should work with minor testing |
| **10.0 - 14.x** | ✅ **Supported** | Compatible with testing |
| **2.0 - 9.x** | ⚠️ **Legacy** | May require additional testing |

**Note**: While the library supports Angular 2.0+, it's primarily tested and optimized for Angular 20+. For production use with older versions, thorough testing is recommended. The library uses relaxed peer dependencies (Angular >=10.0.0) to ensure compatibility across different Angular versions.

### Install Package

```bash
# Using npm
npm install ng2-pdfjs-viewer --save

# Using yarn
yarn add ng2-pdfjs-viewer

# Using pnpm
pnpm add ng2-pdfjs-viewer
```

### Configure Assets

Add PDF.js assets to your `angular.json`:

```json
{
  "projects": {
    "your-app": {
      "architect": {
        "build": {
          "options": {
            "assets": [
              {
                "glob": "**/*",
                "input": "node_modules/ng2-pdfjs-viewer/pdfjs",
                "output": "/assets/pdfjs"
              }
            ]
          }
        }
      }
    }
  }
}
```

---

## 🎯 Basic Usage

### Simple PDF Viewer

```html
<ng2-pdfjs-viewer pdfSrc="assets/document.pdf" [showSpinner]="true">
</ng2-pdfjs-viewer>
```

### Advanced Configuration

```html
<ng2-pdfjs-viewer
  pdfSrc="assets/document.pdf"
  [theme]="'dark'"
  [primaryColor]="'#007acc'"
  [showSpinner]="true"
  [customSpinnerTpl]="customSpinner"
  [customErrorTpl]="customError"
  (onDocumentLoad)="onDocumentLoaded($event)"
  (onPageChange)="onPageChanged($event)"
>
</ng2-pdfjs-viewer>
```

### Security Configuration

```html
<!-- Basic security (default enabled) -->
<ng2-pdfjs-viewer 
  pdfSrc="assets/document.pdf"
  [urlValidation]="true">
</ng2-pdfjs-viewer>

<!-- Custom security template -->
<ng2-pdfjs-viewer 
  pdfSrc="assets/document.pdf"
  [urlValidation]="true"
  [customSecurityTpl]="securityTemplate">
</ng2-pdfjs-viewer>

<ng-template #securityTemplate let-warning="securityWarning">
  <div class="alert alert-warning" *ngIf="warning">
    <h4>⚠️ Security Warning</h4>
    <p>{{ warning.message }}</p>
    <button (click)="pdfViewer.dismissSecurityWarning()">Dismiss</button>
  </div>
</ng-template>
```

### Programmatic Control

```typescript
import { Component, ViewChild } from "@angular/core";
import { PdfJsViewerComponent } from "ng2-pdfjs-viewer";

@Component({
  template: `
    <ng2-pdfjs-viewer #pdfViewer pdfSrc="document.pdf"></ng2-pdfjs-viewer>
    <button (click)="goToPage(5)">Go to Page 5</button>
  `,
})
export class MyComponent {
  @ViewChild("pdfViewer") pdfViewer!: PdfJsViewerComponent;

  async goToPage(page: number) {
    await this.pdfViewer.goToPage(page);
  }
}
```

---

## Advanced Configuration

### Theme Customization

```typescript
// Component
export class MyComponent {
  themeConfig = {
    theme: "light",
    primaryColor: "#007acc",
    backgroundColor: "#ffffff",
    toolbarColor: "#f5f5f5",
    textColor: "#333333",
    borderRadius: "8px",
  };
}
```

```html
<!-- Template -->
<ng2-pdfjs-viewer [themeConfig]="themeConfig" [customCSS]="customStyles">
</ng2-pdfjs-viewer>
```

### Custom Loading Spinner

```html
<ng-template #customSpinner>
  <div class="custom-spinner">
    <div class="spinner"></div>
    <p>Loading PDF...</p>
  </div>
</ng-template>

<ng2-pdfjs-viewer
  [customSpinnerTpl]="customSpinner"
  [spinnerClass]="'my-spinner'"
>
</ng2-pdfjs-viewer>
```

### Custom Error Display

```html
<ng-template #customError>
  <div class="error-container">
    <mat-icon>error</mat-icon>
    <h3>Failed to Load PDF</h3>
    <p>Please check your internet connection and try again.</p>
    <button mat-button (click)="retry()">Retry</button>
  </div>
</ng-template>

<ng2-pdfjs-viewer [customErrorTpl]="customError" [errorClass]="'my-error'">
</ng2-pdfjs-viewer>
```

### External Window Behavior

```html
<!-- Basic external window (reuses same tab) -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf"
  [externalWindow]="true">
</ng2-pdfjs-viewer>

<!-- Custom window options -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf"
  [externalWindow]="true"
  [externalWindowOptions]="'width=1200,height=800,scrollbars=yes,resizable=yes'">
</ng2-pdfjs-viewer>

<!-- Force new tab each time -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf"
  [externalWindow]="true"
  [target]="'pdf-viewer-' + Date.now()">
</ng2-pdfjs-viewer>
```

**Tab Reuse Behavior:**
- **Same `target` name** → Reuses existing tab (default behavior)
- **Unique `target` name** → Always opens new tab
- **`target="_blank"`** → Browser decides (usually reuses)

### iframe Security

```html
<!-- Built-in security (always enabled) -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf">
</ng2-pdfjs-viewer>
```

**Built-in Security Features:**
- **Static Sandbox** - `allow-forms allow-scripts allow-same-origin allow-modals`
- **XSS Prevention** - Prevents malicious scripts from affecting parent page
- **CSP Compliance** - Meets Content Security Policy requirements
- **Data Protection** - Limits iframe access to parent window context
- **Enterprise Ready** - Suitable for corporate security environments

**Sandbox Attributes (Fixed for Security):**
- `allow-forms` - Required for PDF form functionality
- `allow-scripts` - Required for PDF.js JavaScript execution
- `allow-same-origin` - Required for loading PDF files and assets
- `allow-modals` - Required for PDF.js dialogs (print, download)

### iframe Styling

```html
<!-- Default (no border) -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf">
</ng2-pdfjs-viewer>

<!-- Custom border -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf"
  iframeBorder="2px solid #ccc">
</ng2-pdfjs-viewer>

<!-- Numeric border -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf"
  [iframeBorder]="1">
</ng2-pdfjs-viewer>

<!-- No border (explicit) -->
<ng2-pdfjs-viewer 
  pdfSrc="document.pdf"
  iframeBorder="0">
</ng2-pdfjs-viewer>
```

---

## 📚 API Reference

### Input Properties

| Property                     | Type                                      | Default      | Description                           |
| ---------------------------- | ----------------------------------------- | ------------ | ------------------------------------- |
| `pdfSrc`                     | `string \| Blob \| Uint8Array`            | -            | PDF source (URL, Blob, or byte array) |
| `viewerId`                   | `string`                                  | auto         | Unique viewer identifier              |
| `viewerFolder`               | `string`                                  | `'assets'`   | Path to PDF.js assets                 |
| `externalWindow`             | `boolean`                                 | `false`      | Open in new window                    |
| `externalWindowOptions`      | `string`                                  | -            | External window options (size, position, etc.) |
| `target`                     | `string`                                  | `'_blank'`   | Target for external window (controls tab reuse) |
| `theme`                      | `'light' \| 'dark' \| 'auto'`             | `'light'`    | Theme selection                       |
| `primaryColor`               | `string`                                  | `'#007acc'`  | Primary color for UI elements         |
| `backgroundColor`            | `string`                                  | `'#ffffff'`  | Background color                      |
| `pageBorderColor`            | `string`                                  | -            | Page border color                     |
| `toolbarColor`               | `string`                                  | -            | Toolbar background color              |
| `textColor`                  | `string`                                  | -            | Text color                            |
| `borderRadius`               | `string`                                  | -            | Border radius                         |
| `customCSS`                  | `string`                                  | -            | Custom CSS styles                     |
| `cspNonce`                   | `string`                                  | -            | CSP nonce for customCSS (optional)    |
| `iframeTitle`                | `string`                                  | -            | Accessible title for iframe (optional) |
| `showSpinner`                | `boolean`                                 | `true`       | Show loading spinner                  |
| `customSpinnerTpl`           | `TemplateRef`                             | -            | Custom spinner template               |
| `spinnerClass`               | `string`                                  | -            | Custom spinner CSS class              |
| `customErrorTpl`             | `TemplateRef`                             | -            | Custom error template                 |
| `errorClass`                 | `string`                                  | -            | Custom error CSS class                |
| `errorOverride`              | `boolean`                                 | `false`      | Override default error handling       |
| `errorAppend`                | `boolean`                                 | `true`       | Append to default error messages      |
| `errorMessage`               | `string`                                  | -            | Custom error message                  |
| `locale`                     | `string`                                  | `'en-US'`    | UI language                           |
| `useOnlyCssZoom`             | `boolean`                                 | `false`      | Use CSS-based zoom for mobile         |
| `diagnosticLogs`             | `boolean`                                 | `false`      | Enable diagnostic logging             |
| `zoom`                       | `string`                                  | `'auto'`     | Initial zoom level (two-way binding)  |
| `page`                       | `number`                                  | `1`          | Initial page number                   |
| `namedDest`                  | `string`                                  | -            | Named destination to navigate to      |
| `cursor`                     | `string`                                  | `'select'`   | Cursor type (two-way binding)         |
| `scroll`                     | `string`                                  | `'vertical'` | Scroll mode (two-way binding)         |
| `spread`                     | `string`                                  | `'none'`     | Spread mode (two-way binding)         |
| `pageMode`                   | `string`                                  | `'none'`     | Page mode (two-way binding)           |
| `rotation`                   | `number`                                  | `0`          | Document rotation (two-way binding)   |
| `showOpenFile`               | `boolean`                                 | `true`       | Show open file button                 |
| `showDownload`               | `boolean`                                 | `true`       | Show download button                  |
| `showPrint`                  | `boolean`                                 | `true`       | Show print button                     |
| `showFind`                   | `boolean`                                 | `true`       | Show search button                    |
| `showFullScreen`             | `boolean`                                 | `true`       | Show fullscreen button                |
| `showViewBookmark`           | `boolean`                                 | `true`       | Show bookmark button                  |
| `showAnnotations`            | `boolean`                                 | `false`      | Show annotations                      |
| `showToolbarLeft`            | `boolean`                                 | `true`       | Show left toolbar section             |
| `showToolbarMiddle`          | `boolean`                                 | `true`       | Show middle toolbar section           |
| `showToolbarRight`           | `boolean`                                 | `true`       | Show right toolbar section            |
| `showSecondaryToolbarToggle` | `boolean`                                 | `true`       | Show secondary toolbar toggle         |
| `showSidebar`                | `boolean`                                 | `true`       | Show sidebar                          |
| `showSidebarLeft`            | `boolean`                                 | `true`       | Show left sidebar                     |
| `showSidebarRight`           | `boolean`                                 | `true`       | Show right sidebar                    |
| `toolbarDensity`             | `'compact' \| 'default' \| 'comfortable'` | `'default'`  | Toolbar density                       |
| `sidebarWidth`               | `string`                                  | -            | Sidebar width (e.g., '280px')         |
| `toolbarPosition`            | `'top' \| 'bottom'`                       | `'top'`      | Toolbar position                      |
| `sidebarPosition`            | `'left' \| 'right'`                       | `'left'`     | Sidebar position                      |
| `responsiveBreakpoint`       | `string \| number`                        | -            | Responsive breakpoint                 |
| `downloadOnLoad`             | `boolean`                                 | `false`      | Auto-download on load                 |
| `printOnLoad`                | `boolean`                                 | `false`      | Auto-print on load                    |
| `rotateCW`                   | `boolean`                                 | `false`      | Rotate clockwise on load              |
| `rotateCCW`                  | `boolean`                                 | `false`      | Rotate counter-clockwise on load      |
| `showLastPageOnLoad`         | `boolean`                                 | `false`      | Go to last page on load               |
| `downloadFileName`           | `string`                                  | -            | Custom download filename              |
| `controlVisibility`          | `ControlVisibilityConfig`                 | -            | Control visibility configuration      |
| `autoActions`                | `AutoActionConfig`                        | -            | Auto actions configuration            |
| `errorHandling`              | `ErrorConfig`                             | -            | Error handling configuration          |
| `viewerConfig`               | `ViewerConfig`                            | -            | Viewer configuration                  |
| `themeConfig`                | `ThemeConfig`                             | -            | Theme configuration                   |
| `groupVisibility`            | `GroupVisibilityConfig`                   | -            | Group visibility configuration        |
| `layoutConfig`               | `LayoutConfig`                            | -            | Layout configuration                  |
| `urlValidation`              | `boolean`                                 | `true`       | Enable URL validation                 |
| `customSecurityTpl`          | `TemplateRef<any>`                        | -            | Custom security template              |
| `securityWarning`            | `SecurityWarning \| null`                 | -            | Security warning data (read-only)     |
| `iframeBorder`               | `string \| number`                        | `"0"`        | iframe border style                   |

### Output Events

| Event                       | Type                                       | Description                                    |
| --------------------------- | ------------------------------------------ | ---------------------------------------------- |
| `onDocumentLoad`            | `EventEmitter<void>`                       | Fired when document loads                      |
| `onDocumentInit`            | `EventEmitter<void>`                       | Fired when document initializes                |
| `onDocumentError`           | `EventEmitter<DocumentError>`              | Fired when document fails to load              |
| `onPageChange`              | `EventEmitter<ChangedPage>`                | Fired when page changes                        |
| `onPagesInit`               | `EventEmitter<PagesInfo>`                  | Fired when pages are initialized               |
| `onPageRendered`            | `EventEmitter<PageRenderInfo>`             | Fired when a page is rendered                  |
| `onScaleChange`             | `EventEmitter<ChangedScale>`               | Fired when zoom/scale changes                  |
| `onRotationChange`          | `EventEmitter<ChangedRotation>`            | Fired when rotation changes                    |
| `onPresentationModeChanged` | `EventEmitter<PresentationMode>`           | Fired when presentation mode changes           |
| `onOpenFile`                | `EventEmitter<void>`                       | Fired when open file is clicked                |
| `onFind`                    | `EventEmitter<FindOperation>`              | Fired when search is performed                 |
| `onUpdateFindMatchesCount`  | `EventEmitter<FindMatchesCount>`           | Fired when search matches are updated          |
| `onMetadataLoaded`          | `EventEmitter<DocumentMetadata>`           | Fired when document metadata loads             |
| `onOutlineLoaded`           | `EventEmitter<DocumentOutline>`            | Fired when document outline loads              |
| `onAnnotationLayerRendered` | `EventEmitter<AnnotationLayerRenderEvent>` | Fired when annotation layer renders            |
| `onBookmarkClick`           | `EventEmitter<BookmarkClick>`              | Fired when bookmark is clicked                 |
| `onIdle`                    | `EventEmitter<void>`                       | Fired when viewer becomes idle                 |
| `onBeforePrint`             | `EventEmitter<void>`                       | Fired before printing                          |
| `onAfterPrint`              | `EventEmitter<void>`                       | Fired after printing                           |
| `zoomChange`                | `EventEmitter<string>`                     | Fired when zoom changes (two-way binding)      |
| `cursorChange`              | `EventEmitter<string>`                     | Fired when cursor changes (two-way binding)    |
| `scrollChange`              | `EventEmitter<string>`                     | Fired when scroll changes (two-way binding)    |
| `spreadChange`              | `EventEmitter<string>`                     | Fired when spread changes (two-way binding)    |
| `pageModeChange`            | `EventEmitter<string>`                     | Fired when page mode changes (two-way binding) |

### Methods

| Method                                                   | Parameters                                                  | Returns                                              | Description                       |
| -------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------- | --------------------------------- |
| `refresh()`                                              | -                                                           | `void`                                               | Refresh viewer                    |
| `goToPage(page: number)`                                 | `page: number`                                              | `Promise<ActionExecutionResult>`                     | Navigate to specific page         |
| `setPage(page: number)`                                  | `page: number`                                              | `Promise<ActionExecutionResult>`                     | Set current page                  |
| `setZoom(zoom: string)`                                  | `zoom: string`                                              | `Promise<ActionExecutionResult>`                     | Set zoom level                    |
| `setCursor(cursor: string)`                              | `cursor: 'select' \| 'hand' \| 'zoom'`                      | `Promise<ActionExecutionResult>`                     | Set cursor type                   |
| `setScroll(scroll: string)`                              | `scroll: 'vertical' \| 'horizontal' \| 'wrapped' \| 'page'` | `Promise<ActionExecutionResult>`                     | Set scroll mode                   |
| `setSpread(spread: string)`                              | `spread: 'none' \| 'odd' \| 'even'`                         | `Promise<ActionExecutionResult>`                     | Set spread mode                   |
| `setPageMode(mode: string)`                              | `mode: 'none' \| 'thumbs' \| 'bookmarks' \| 'attachments'`  | `Promise<ActionExecutionResult>`                     | Set page mode                     |
| `triggerDownload()`                                      | -                                                           | `Promise<ActionExecutionResult>`                     | Trigger download                  |
| `triggerPrint()`                                         | -                                                           | `Promise<ActionExecutionResult>`                     | Trigger print                     |
| `triggerRotation(direction: string)`                     | `direction: 'cw' \| 'ccw'`                                  | `Promise<ActionExecutionResult>`                     | Rotate document                   |
| `goToLastPage()`                                         | -                                                           | `Promise<ActionExecutionResult>`                     | Navigate to last page             |
| `sendViewerControlMessage(action: string, payload: any)` | `action: string, payload: any`                              | `Promise<any>`                                       | Send custom control message       |
| `getActionStatus(actionId: string)`                      | `actionId: string`                                          | `Promise<ActionExecutionResult \| null>`             | Get action status                 |
| `getQueueStatus()`                                       | -                                                           | `{ queuedActions: number; executedActions: number }` | Get queue status                  |
| `clearActionQueue()`                                     | -                                                           | `void`                                               | Clear action queue                |
| `reloadViewer()`                                         | -                                                           | `void`                                               | Reload viewer (alias for refresh) |
| `goBack()`                                               | -                                                           | `void`                                               | Go back in browser history        |
| `closeViewer()`                                          | -                                                           | `void`                                               | Close viewer window               |
| `getErrorTemplateData()`                                 | -                                                           | `any`                                                | Get error template data           |
| `setUrlValidation(enabled: boolean)`                     | `enabled: boolean`                                          | `Promise<ActionExecutionResult>`                     | Enable/disable URL validation     |
| `dismissSecurityWarning()`                               | -                                                           | `void`                                               | Dismiss security warning          |

---

## 🎨 Examples

> **🎯 Live Demo**: [https://angular-pdf-viewer-demo.vercel.app/](https://angular-pdf-viewer-demo.vercel.app/)  
> **📚 Documentation**: [https://angular-pdf-viewer-docs.vercel.app/](https://angular-pdf-viewer-docs.vercel.app/)  
> **📁 Source Code**: [https://github.com/intbot/ng2-pdfjs-viewer/tree/main/SampleApp](https://github.com/intbot/ng2-pdfjs-viewer/tree/main/SampleApp)

### 1. Basic PDF Viewer

```html
<ng2-pdfjs-viewer pdfSrc="assets/sample.pdf" [showSpinner]="true">
</ng2-pdfjs-viewer>
```

### 2. Themed PDF Viewer

```html
<ng2-pdfjs-viewer
  pdfSrc="assets/sample.pdf"
  [theme]="'dark'"
  [primaryColor]="'#ff6b6b'"
  [backgroundColor]="'#2c3e50'"
>
</ng2-pdfjs-viewer>
```

### 3. Custom Loading & Error

```html
<ng-template #loadingTemplate>
  <div class="loading">
    <mat-spinner></mat-spinner>
    <p>Loading your document...</p>
</div>
</ng-template>

<ng-template #errorTemplate>
  <div class="error">
    <mat-icon>error_outline</mat-icon>
    <h3>Oops! Something went wrong</h3>
    <p>We couldn't load your PDF. Please try again.</p>
    <button mat-button (click)="retry()">Retry</button>
</div>
</ng-template>

<ng2-pdfjs-viewer
  pdfSrc="assets/sample.pdf"
  [customSpinnerTpl]="loadingTemplate"
  [customErrorTpl]="errorTemplate"
>
  </ng2-pdfjs-viewer>
```

### 4. Convenience Setters (Object-Based Configuration)

```typescript
export class PdfController {
  // Group visibility configuration
  groupVisibility = {
    "download": true,
    "print": true,
    "find": true,
    "fullScreen": true,
    "openFile": true,
    "viewBookmark": true,
    "annotations": false
  };

  // Auto actions configuration
  autoActions = {
    "downloadOnLoad": false,
    "printOnLoad": false
  };

  // Control visibility configuration
  controlVisibility = {
    "showToolbarLeft": true,
    "showToolbarMiddle": true,
    "showToolbarRight": true,
    "showSecondaryToolbarToggle": true,
    "showSidebar": true,
    "showSidebarLeft": true,
    "showSidebarRight": true
  };
}
```

```html
<ng2-pdfjs-viewer
  pdfSrc="assets/sample.pdf"
  [groupVisibility]="groupVisibility"
  [autoActions]="autoActions"
  [controlVisibility]="controlVisibility"
>
</ng2-pdfjs-viewer>
```

### 5. Programmatic Control

```typescript
export class PdfController {
  @ViewChild("pdfViewer") pdfViewer!: PdfJsViewerComponent;

  async loadDocument(url: string) {
    this.pdfViewer.pdfSrc = url;
    await this.pdfViewer.refresh();
  }

  async goToPage(page: number) {
    await this.pdfViewer.goToPage(page);
  }

  async setZoom(zoom: string) {
    await this.pdfViewer.setZoom(zoom);
  }
}
```

### 6. Server-Side Integration

For server-side developers, we provide comprehensive examples for integrating PDF APIs with ng2-pdfjs-viewer:

**[📋 Server-Side Examples](../Server-Side-Examples.md)** - Complete examples for:
- **ASP.NET Core (C#)** - RDLC reports, physical files, iTextSharp
- **Node.js (Express)** - File serving, PDFKit, Puppeteer
- **Python (FastAPI)** - ReportLab, WeasyPrint, file handling
- **Java (Spring Boot)** - iText, JasperReports, file serving
- **PHP (Laravel)** - TCPDF, DomPDF, file management
- **Go (Gin)** - gofpdf, file serving, PDF generation

Each example includes proper Content-Type headers, error handling, CORS configuration, and Angular integration patterns.

---

## 🔄 Migration Guide

### From v20.x to v25.x

#### Breaking Changes

1. **PDF.js Upgrade**: Updated to v5.3.93 - some APIs may have changed
2. **Theme System**: New theme properties replace old styling options
3. **Error Handling**: Template-based error system replaces HTML strings

#### Migration Steps

1. **Update Dependencies**

   ```bash
   npm install ng2-pdfjs-viewer@latest
   ```

2. **Update Theme Configuration**

   ```typescript
   // Old way
   [customCSS]="'body { background: red; }'"
   
   // New way
   [theme]="'light'"
   [primaryColor]="'#ff0000'"
   [backgroundColor]="'#ffffff'"
   ```

3. **Update Error Handling**

   ```html
   <!-- Old way -->
   [errorHtml]="'<div>Custom error</div>'"

   <!-- New way -->
   <ng-template #errorTemplate>
     <div>Custom error</div>
   </ng-template>
   <ng2-pdfjs-viewer [customErrorTpl]="errorTemplate"></ng2-pdfjs-viewer>
   ```

4. **Update Spinner Handling**

   ```html
   <!-- Old way -->
   [spinnerHtml]="'<div class=\"spinner\">Loading...</div>'"

   <!-- New way -->
   <ng-template #spinnerTemplate>
     <div class="spinner">Loading...</div>
   </ng-template>
   <ng2-pdfjs-viewer [customSpinnerTpl]="spinnerTemplate"></ng2-pdfjs-viewer>
   ```

   ```typescript
   // Old way
   this.pdfViewer.setSpinnerHtml('<div>Loading...</div>');

   // New way
   // Use [customSpinnerTpl] with ng-template
   ```

---

## Deprecated Features

The following features are deprecated and will be removed in future versions:

### Deprecated Properties

| Deprecated        | Replacement          | Description                                   |
| ----------------- | -------------------- | --------------------------------------------- |
| `[startDownload]` | `[downloadOnLoad]`   | Download document automatically when it opens |
| `[startPrint]`    | `[printOnLoad]`      | Print document automatically when it opens    |
| `[errorHtml]`     | `[customErrorTpl]`   | Custom error HTML (use template instead)      |
| `[errorTemplate]` | `[customErrorTpl]`   | Custom error template (renamed)               |
| `[spinnerHtml]`   | `[customSpinnerTpl]` | Custom spinner HTML (use template instead)    |

### Deprecated Methods

| Deprecated         | Replacement              | Description                                    |
| ------------------ | ------------------------ | ---------------------------------------------- |
| `setErrorHtml()`   | Use `[customErrorTpl]`   | Set custom error HTML (use template instead)   |
| `setSpinnerHtml()` | Use `[customSpinnerTpl]` | Set custom spinner HTML (use template instead) |

### Migration Help

```typescript
// Deprecated - Error Handling
this.pdfViewer.setErrorHtml("<div>Error</div>");

// New way - Error Handling
// Use [customErrorTpl] with ng-template

// Deprecated - Spinner Handling
this.pdfViewer.setSpinnerHtml("<div>Loading...</div>");

// New way - Spinner Handling
// Use [customSpinnerTpl] with ng-template
```

---

## 📚 Additional Resources

- **[Custom CSS Examples](Custom-CSS-Examples.md)** - Complete styling guide with theme customization examples
- **[Error Display Examples](Error-Display-Examples.md)** - Custom error template examples and styling options
- **[Contributing Guide](CONTRIBUTING.md)** - How to contribute to the project

## 🤝 Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

### Development Setup

```bash
# Clone the repository
git clone https://github.com/intbot/ng2-pdfjs-viewer.git


# Clear Angular cache (Windows)
Remove-Item -Recurse -Force "SampleApp\.angular"


# Build and test - All at once (Windows)
@test.bat
```


---

## 📄 License

This project is licensed under the **Apache License 2.0 + Commons Clause License Condition v1.0** - see the [LICENSE](LICENSE) file for details.

---

## 🙏 Acknowledgments



- **Community Contributors** - For bug reports, feature requests, and contributions
- **7+ Million Users** - For trusting us with your PDF viewing needs
- **Mozilla PDF.js Team** - For the amazing PDF.js library

---

## 📞 Support

- 📖 **Documentation**: [GitHub Wiki](https://github.com/intbot/ng2-pdfjs-viewer/wiki)
- 💬 **Community**: [GitHub Discussions](https://github.com/intbot/ng2-pdfjs-viewer/discussions)
- 🐛 **Issues**: [GitHub Issues](https://github.com/intbot/ng2-pdfjs-viewer/issues)
- 📧 **Email**: codehippie1@gmail.com
- 👨‍💻 **Author**: [Aneesh Gopalakrishnan](http://github.com/codehippie1)

---

<div align="center">


## 🔒 Security

I take security of this library seriously. If you discover a security vulnerability, please report it privately:

- **🔒 Private Reporting**: [Security Policy](https://github.com/intbot/ng2-pdfjs-viewer/security/policy)
- **📧 Email**: [codehippie1@gmail.com](mailto:codehippie1@gmail.com)
- **⚠️ Please do NOT** report security issues through public GitHub issues

For security best practices and vulnerability reporting guidelines, see our [Security Policy](https://github.com/intbot/ng2-pdfjs-viewer/security/policy).

---

[![GitHub](https://img.shields.io/badge/GitHub-Repository-blue?logo=github)](https://github.com/intbot/ng2-pdfjs-viewer)
[![NPM](https://img.shields.io/badge/NPM-Package-red?logo=npm)](https://www.npmjs.com/package/ng2-pdfjs-viewer)
[![Angular](https://img.shields.io/badge/Angular-Component-green?logo=angular)](https://angular.dev/overview)

</div>
