Angular  

Implementing Custom File Viewer (PDF, Images, Videos, DOCX) in Angular Without iFrame

Modern web applications require a smooth and secure way to preview files such as PDFs, images, videos, and DOCX documents. Traditionally, developers use the <iframe> tag to embed these files. However, iframes come with problems like poor mobile support, browser restrictions, limited styling, and cross-origin issues.

This article explains how to build a fully custom file viewer in Angular without using any iframe, using native HTML elements and specialised libraries.

Objective of This Article

  • Build a unified file viewer in Angular

  • Support PDF, images, videos, and DOCX

  • Avoid <iframe> completely

  • Provide clean UI and modular code

  • Deliver a reusable component that works in any Angular project

Overall Architecture

Architecture Diagram (Visio-Style)

                 +-----------------------------+
                 |         Angular App         |
                 +-----------------------------+
                           |  Requests File
                           v
                +--------------------------------+
                |     File Viewer Component      |
                +--------------------------------+
                  |     |        |        |
                  |     |        |        |
                  v     v        v        v
         +--------+  +-------+ +------+ +---------+
         | PDF     | | Image | | Video | | DOCX    |
         | Rendering| | Viewer| | Player| | Viewer |
         +----------+ +-------+ +------+ +---------+
                  |
                  | requests binary file
                  v
        +------------------------------+
        |     ASP.NET Core Backend     |
        | (File fetch, binary output)  |
        +------------------------------+
                  |
                  v
        +------------------------------+
        |     SQL Server / Storage     |
        +------------------------------+

ER Diagram (Storage Structure)

Most systems store metadata only and the file itself in disk/cloud.

+----------------------------+
|          FileMeta          |
+----------------------------+
| FileId (PK)                |
| FileName                   |
| FileType                   |
| FileSize                   |
| StoragePath                |
| UploadedBy                 |
| UploadedOn                 |
+----------------------------+

Workflow Diagram

User selects file
        |
        v
Angular component detects file type
        |
        +--> PDF? -----> Render using pdf-lib / pdfjs-dist
        |
        +--> Image? -----> Render using <img> tag
        |
        +--> Video? -----> Render using <video> tag
        |
        +--> DOCX? -----> Convert to HTML using docx-preview
                          and display in custom container

Flowchart

             +---------------------+
             |  Load file metadata |
             +---------------------+
                        |
                        v
            +--------------------------+
            | Identify file extension  |
            +--------------------------+
     .----------|-----------|-----------|-----------.
     v          v           v           v           v
 +--------+ +--------+ +----------+ +----------+ +--------+
 |  PDF   | | Image  | |  Video   | |  DOCX    | | Others |
 +--------+ +--------+ +----------+ +----------+ +--------+
     |          |          |            |           |
Render PDF  Show <img>  Show <video> Convert DOCX  Show error/
component     tag        tag         to HTML        download-only

Sequence Diagram (File Rendering)

User ----> Angular Component: Request to open file
Angular Component ----> Backend API: Fetch file binary
Backend API ----> Storage: Read file
Storage ----> Backend API: Return file stream
Backend API ----> Angular Component: Binary file + metadata
Angular Component ----> FileViewerService: Detect file type
FileViewerService ----> Angular Components: Render appropriate viewer

Building the File Viewer in Angular

Step 1: Create a unified file-viewer component

ng g c shared/file-viewer

Step 2: HTML Structure Without Iframe

file-viewer.component.html

<div *ngIf="fileType === 'pdf'">
  <canvas #pdfCanvas class="pdf-canvas"></canvas>
</div>

<div *ngIf="fileType === 'image'">
  <img [src]="fileUrl" class="image-viewer">
</div>

<div *ngIf="fileType === 'video'">
  <video [src]="fileUrl" controls class="video-player"></video>
</div>

<div *ngIf="fileType === 'docx'">
  <div #docxContainer class="docx-container"></div>
</div>

<div *ngIf="fileType === 'unknown'">
  <p>Unsupported file type. Download instead.</p>
</div>

Step 3: Component TypeScript Logic

file-viewer.component.ts

import { Component, Input, ElementRef, ViewChild, OnInit } from '@angular/core';
import { DocumentViewerService } from './services/document-viewer.service';

@Component({
  selector: 'app-file-viewer',
  templateUrl: './file-viewer.component.html',
  styleUrls: ['./file-viewer.component.scss']
})
export class FileViewerComponent implements OnInit {

  @Input() fileUrl!: string;
  @ViewChild('pdfCanvas') pdfCanvas!: ElementRef<HTMLCanvasElement>;
  @ViewChild('docxContainer') docxContainer!: ElementRef<HTMLDivElement>;

  fileType: string = 'unknown';

  constructor(private viewer: DocumentViewerService) { }

  ngOnInit() {
    this.detectType();

    if (this.fileType === 'pdf') {
      this.viewer.renderPdf(this.fileUrl, this.pdfCanvas);
    }

    if (this.fileType === 'docx') {
      this.viewer.renderDocx(this.fileUrl, this.docxContainer);
    }
  }

  detectType() {
    const ext = this.fileUrl.split('.').pop()?.toLowerCase();

    if (ext === 'pdf') this.fileType = 'pdf';
    else if (['jpg','jpeg','png','gif','bmp'].includes(ext!)) this.fileType = 'image';
    else if (['mp4','webm','mov'].includes(ext!)) this.fileType = 'video';
    else if (['docx'].includes(ext!)) this.fileType = 'docx';
    else this.fileType = 'unknown';
  }
}

Step 4: PDF Rendering (without iframe)

Install supporting library

npm install pdfjs-dist

document-viewer.service.ts

import { Injectable } from '@angular/core';
import * as pdfjsLib from 'pdfjs-dist';

pdfjsLib.GlobalWorkerOptions.workerSrc = `./assets/pdf.worker.min.js`;

@Injectable({ providedIn: 'root' })
export class DocumentViewerService {

  async renderPdf(url: string, canvasRef: any) {
    const pdf = await pdfjsLib.getDocument(url).promise;
    const page = await pdf.getPage(1);

    const viewport = page.getViewport({ scale: 1.2 });
    const canvas = canvasRef.nativeElement;
    const context = canvas.getContext('2d');

    canvas.height = viewport.height;
    canvas.width = viewport.width;

    await page.render({
      canvasContext: context,
      viewport: viewport
    }).promise;
  }
}

Step 5: DOCX Rendering (No iframe)

Install

npm install docx-preview

Add to service

import { renderAsync } from 'docx-preview';

async renderDocx(url: string, containerRef: any) {
  const response = await fetch(url);
  const blob = await response.blob();
  renderAsync(blob, containerRef.nativeElement);
}

This library converts DOCX into pure HTML.

Step 6: Styling

file-viewer.component.scss

.pdf-canvas {
  width: 100%;
  border: 1px solid #ccc;
}

.image-viewer {
  max-width: 100%;
  height: auto;
}

.video-player {
  width: 100%;
  max-height: 480px;
}

.docx-container {
  padding: 20px;
  background: #f8f8f8;
}

Step 7: Example Usage

<app-file-viewer
    [fileUrl]="'https://myserver.com/files/sample.pdf'">
</app-file-viewer>

Backend (ASP.NET Core) – File Delivery API

[HttpGet("file/{id}")]
public IActionResult GetFile(Guid id)
{
    var file = _db.FileMeta.Find(id);
    if (file == null) return NotFound();

    var bytes = System.IO.File.ReadAllBytes(file.StoragePath);
    return File(bytes, GetMimeType(file.FileType), file.FileName);
}

Best Practices

  • Always stream files instead of loading into memory

  • Use secure URLs with token-based expiry

  • Limit DOCX size to avoid heavy conversions

  • Cache PDF pages for performance

  • Never allow direct file path access

  • Sanitise extensions to avoid unsafe file execution

Final Summary

By combining built-in HTML elements and specialised libraries such as pdfjs-dist and docx-preview, we can create a powerful, secure, and responsive file viewer in Angular without using any iframe. This approach gives full control over the UI, allows customisation, and avoids iframe-specific problems.