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.