The File Upload component provides an intuitive interface for uploading files with support for drag-and-drop, multiple files, validation, and upload progress.
Basic usage
<flx-file-upload
(filesSelected)="onFilesSelected($event)">
</flx-file-upload>
Properties
Accepted file types (e.g., ‘image/*’, ‘.pdf,.doc’)
Allow multiple file selection
Maximum file size in bytes
Maximum number of files allowed
Enable drag-and-drop functionality
Show list of selected files
Show upload progress indicators
Start upload automatically when files are selected
Events
Emitted when files are selected
Emitted when a file is removed from the list
uploadProgress
EventEmitter<UploadProgress>
Emitted during file upload with progress information
uploadComplete
EventEmitter<UploadResult>
Emitted when upload completes
Emitted when upload fails
Examples
Basic upload
Image upload only
With validation
With progress
Auto upload
Custom template
<flx-file-upload
(filesSelected)="handleFiles($event)">
</flx-file-upload>
<button
*ngIf="selectedFiles.length > 0"
(click)="upload()">
Upload {{ selectedFiles.length }} file(s)
</button>
export class FileUploadExample {
selectedFiles: File[] = [];
handleFiles(files: File[]) {
this.selectedFiles = files;
}
async upload() {
for (const file of this.selectedFiles) {
await this.uploadFile(file);
}
}
async uploadFile(file: File) {
const formData = new FormData();
formData.append('file', file);
await this.http.post('/api/upload', formData).toPromise();
}
}
<flx-file-upload
accept="image/*"
[multiple]="true"
[maxSize]="5 * 1024 * 1024"
(filesSelected)="onImagesSelected($event)">
</flx-file-upload>
<div class="image-previews">
<img
*ngFor="let preview of imagePreviews"
[src]="preview"
alt="Preview" />
</div>
export class ImageUpload {
imagePreviews: string[] = [];
onImagesSelected(files: File[]) {
files.forEach(file => {
const reader = new FileReader();
reader.onload = (e) => {
this.imagePreviews.push(e.target?.result as string);
};
reader.readAsDataURL(file);
});
}
}
<flx-file-upload
accept=".pdf,.doc,.docx"
[maxSize]="10 * 1024 * 1024"
[maxFiles]="3"
(filesSelected)="validateAndHandle($event)">
</flx-file-upload>
<flx-message
*ngIf="validationError"
type="error"
[dismissible]="true"
(dismiss)="validationError = null">
{{ validationError }}
</flx-message>
export class ValidatedUpload {
validationError: string | null = null;
maxSizeBytes = 10 * 1024 * 1024; // 10MB
allowedTypes = ['.pdf', '.doc', '.docx'];
validateAndHandle(files: File[]) {
this.validationError = null;
// Check file count
if (files.length > 3) {
this.validationError = 'Maximum 3 files allowed';
return;
}
// Validate each file
for (const file of files) {
// Check size
if (file.size > this.maxSizeBytes) {
this.validationError = `File ${file.name} exceeds 10MB limit`;
return;
}
// Check type
const ext = '.' + file.name.split('.').pop()?.toLowerCase();
if (!this.allowedTypes.includes(ext)) {
this.validationError = `File ${file.name} has invalid type`;
return;
}
}
this.handleValidFiles(files);
}
handleValidFiles(files: File[]) {
console.log('Valid files:', files);
}
}
<flx-file-upload
[showProgress]="true"
(filesSelected)="startUpload($event)"
(uploadProgress)="onProgress($event)"
(uploadComplete)="onComplete($event)"
(uploadError)="onError($event)">
</flx-file-upload>
export class ProgressUpload {
startUpload(files: File[]) {
files.forEach(file => this.uploadWithProgress(file));
}
uploadWithProgress(file: File) {
const formData = new FormData();
formData.append('file', file);
this.http.post('/api/upload', formData, {
reportProgress: true,
observe: 'events'
}).subscribe(event => {
if (event.type === HttpEventType.UploadProgress) {
const progress = Math.round(100 * event.loaded / (event.total || 1));
console.log(`Upload progress: ${progress}%`);
} else if (event.type === HttpEventType.Response) {
console.log('Upload complete!');
}
});
}
onProgress(progress: UploadProgress) {
console.log(`${progress.fileName}: ${progress.percentage}%`);
}
onComplete(result: UploadResult) {
console.log('Upload successful:', result);
}
onError(error: Error) {
console.error('Upload failed:', error);
}
}
<flx-file-upload
[multiple]="true"
[autoUpload]="true"
(uploadComplete)="onUploadComplete($event)">
</flx-file-upload>
<flx-file-upload (filesSelected)="handleFiles($event)">
<ng-template #uploadTemplate>
<div class="custom-upload-area">
<flx-icon name="cloud-upload" size="48"></flx-icon>
<h3>Drop files here</h3>
<p>or click to browse</p>
<p class="hint">Supports PDF, DOC, DOCX up to 10MB</p>
</div>
</ng-template>
</flx-file-upload>
File validation
interface ValidationRules {
accept?: string; // MIME types or extensions
maxSize?: number; // Maximum file size in bytes
maxFiles?: number; // Maximum number of files
minSize?: number; // Minimum file size in bytes
customValidator?: (file: File) => boolean;
}
Styling
flx-file-upload {
--flx-upload-border-color: #d1d5db;
--flx-upload-border-style: dashed;
--flx-upload-border-width: 2px;
--flx-upload-border-radius: 8px;
--flx-upload-background: #f9fafb;
--flx-upload-hover-background: #f3f4f6;
--flx-upload-drag-background: #dbeafe;
--flx-upload-drag-border-color: #3b82f6;
--flx-upload-min-height: 200px;
--flx-upload-progress-color: #3b82f6;
}
Accessibility
The File Upload component ensures accessibility:
- Hidden file input with proper labels
- Keyboard accessible (Enter/Space to trigger)
- Screen reader announcements for file selection
- Focus indicators
- Drag-and-drop feedback
Best practices
- Always validate file types and sizes on both client and server
- Provide clear feedback about accepted file types and size limits
- Show upload progress for better user experience
- Handle errors gracefully with clear messages
- Allow users to remove files before upload
- Consider using thumbnails for image uploads
- Implement chunked uploads for large files
- Provide cancel functionality for ongoing uploads
For optimal user experience, set reasonable maxSize limits and show clear error messages when validation fails.
Always implement server-side validation as client-side checks can be bypassed. Never trust file extensions alone—verify file content.