How to preview images before upload in Angular
Showing a preview before uploading gives users immediate confidence that they selected the right file, dramatically reducing mistakes and re-uploads.
As the creator of CoreUI with Angular development experience since 2014, I include image preview in every avatar upload or gallery feature in CoreUI Angular templates.
The browser’s FileReader API reads the selected file as a Data URL and Angular’s change detection updates the preview image source reactively.
This requires no libraries — just the native File API and a reactive component property.
Use FileReader.readAsDataURL to generate a preview URL from the selected file.
// image-upload.component.ts
import { Component } from '@angular/core'
import { CommonModule } from '@angular/common'
@Component({
selector: 'app-image-upload',
standalone: true,
imports: [CommonModule],
template: `
<div class="upload-container">
<input
type="file"
accept="image/*"
(change)="onFileSelected($event)"
#fileInput
style="display: none"
/>
<div class="preview-area" (click)="fileInput.click()">
<img
*ngIf="previewUrl; else placeholder"
[src]="previewUrl"
alt="Preview"
class="preview-image"
/>
<ng-template #placeholder>
<div class="placeholder">Click to select an image</div>
</ng-template>
</div>
<p *ngIf="error" class="text-danger">{{ error }}</p>
<button
*ngIf="previewUrl"
(click)="upload()"
[disabled]="uploading"
>
{{ uploading ? 'Uploading...' : 'Upload Image' }}
</button>
</div>
`
})
export class ImageUploadComponent {
previewUrl: string | null = null
error = ''
uploading = false
private selectedFile: File | null = null
onFileSelected(event: Event): void {
const input = event.target as HTMLInputElement
const file = input.files?.[0]
if (!file) return
this.error = ''
if (!file.type.startsWith('image/')) {
this.error = 'Please select an image file'
return
}
if (file.size > 5 * 1024 * 1024) {
this.error = 'Image must be smaller than 5MB'
return
}
this.selectedFile = file
this.readFileAsDataUrl(file)
}
private readFileAsDataUrl(file: File): void {
const reader = new FileReader()
reader.onload = (e) => {
this.previewUrl = e.target?.result as string
}
reader.readAsDataURL(file)
}
async upload(): Promise<void> {
if (!this.selectedFile) return
this.uploading = true
const formData = new FormData()
formData.append('image', this.selectedFile)
try {
const res = await fetch('/api/images', { method: 'POST', body: formData })
if (!res.ok) throw new Error('Upload failed')
this.uploading = false
} catch (err: any) {
this.error = err.message
this.uploading = false
}
}
}
FileReader.readAsDataURL converts the file to a Base64 Data URL. Assigning it to previewUrl and binding it to [src] displays the image immediately without any server round trip. The reader.onload callback runs asynchronously — Angular’s zone integration picks up the change automatically.
Preview with Drag and Drop
Accept dropped images and show preview instantly.
@Component({
selector: 'app-drop-image',
standalone: true,
imports: [CommonModule],
template: `
<div
class="drop-zone"
[class.active]="isDragging"
(dragover)="onDragOver($event)"
(dragleave)="isDragging = false"
(drop)="onDrop($event)"
>
<img *ngIf="previewUrl" [src]="previewUrl" alt="Preview" />
<p *ngIf="!previewUrl">Drop an image here</p>
</div>
`
})
export class DropImageComponent {
isDragging = false
previewUrl: string | null = null
onDragOver(event: DragEvent): void {
event.preventDefault()
this.isDragging = true
}
onDrop(event: DragEvent): void {
event.preventDefault()
this.isDragging = false
const file = event.dataTransfer?.files[0]
if (file?.type.startsWith('image/')) {
const reader = new FileReader()
reader.onload = (e) => { this.previewUrl = e.target?.result as string }
reader.readAsDataURL(file)
}
}
}
The drag and drop pattern is identical — just the file source changes from input.files to event.dataTransfer.files. Always call event.preventDefault() in dragover to enable dropping.
Best Practice Note
This is the same preview approach used in CoreUI Angular templates for user avatar uploads and image galleries. For multiple image previews, call readAsDataURL for each file and push results into an array. After previewing, send the actual File object (not the Data URL) to the server — Data URLs are Base64-encoded and roughly 33% larger than the original file. See how to upload files in Angular for the complete upload implementation.



