Build Upload & Download Features in Laravel with a Progress Bar

Ever built a file upload or download feature in Laravel and noticed something’s missing? You click “upload” or “download”… and then nothing. No indicator, no status, just a silent loading process. That’s not the kind of user experience we want, right?

In this tutorial, you’ll learn how to create file upload and download functionality in Laravel with a progress bar, so users know exactly what’s happening behind the scenes. Whether you’re handling large files or just want a more polished app, this guide will walk you through everything — step by step.

Let’s make your Laravel app feel more responsive and professional!

Step 1: Setting Up the Laravel Project

If you don’t have a Laravel project yet, go ahead and create one:

composer create-project laravel/laravel file-progress
cd file-progress
php artisan serve

Step 2: File Upload with Real-time Progress Bar

We’ll use Livewire and Alpine.js to make the progress bar update live without refreshing the page.

Install Livewire

composer require livewire/livewire

Include Livewire in your layout (e.g., resources/views/welcome.blade.php):

<head>
@livewireStyles
</head>
<body>
@livewire('file-upload')
@livewireScripts
</body>

Create a Livewire Component

php artisan make:livewire FileUpload

Update app/Http/Livewire/FileUpload.php:

namespace App\Http\Livewire;
use Livewire\Component;
use Livewire\WithFileUploads;
class FileUpload extends Component
{
use WithFileUploads;
public $file;
public function save()
{
$this->validate([
'file' => 'required|file|max:10240', // max 10MB
]);
$this->file->store('uploads');
session()->flash('message', 'File uploaded successfully!');
}
public function render()
{
return view('livewire.file-upload');
}
}

Then edit resources/views/livewire/file-upload.blade.php:

<div x-data="{ isUploading: false, progress: 0 }"
x-on:livewire-upload-start="isUploading = true"
x-on:livewire-upload-finish="isUploading = false"
x-on:livewire-upload-error="isUploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress">
<form wire:submit="save">
<input type="file" wire:model="file">
<div x-show="isUploading" class="my-2">
<progress max="100" x-bind:value="progress" class="w-full"></progress>
<p class="text-sm text-gray-600">Progress: <span x-text="progress"></span>%</p>
</div>
<button type="submit">Upload</button>
</form>
@if (session()->has('message'))
<p class="text-green-600 mt-2">{{ session('message') }}</p>
@endif
</div>

Step 3: Download File with Progress Bar

By default, downloading files via browser doesn’t give much feedback. So we’ll use XMLHttpRequest in JavaScript to show download progress.

Laravel Route for Download

Add this to your web.php:

use Illuminate\Support\Facades\Response;
Route::get('/download/{filename}', function ($filename) {
$path = storage_path("app/uploads/{$filename}");
if (!file_exists($path)) {
abort(404);
}
return response()->download($path);
});

HTML + JS for Download Progress

Place this in your Blade view:

<div>
<button onclick="downloadFile('sample_file.pdf')">Download File</button>
<div id="downloadProgress" style="width: 100%; background: #eee; height: 20px; margin-top: 10px;">
<div id="bar" style="height: 100%; width: 0%; background: #4caf50;"></div>
</div>
</div>
<script>
function downloadFile(filename) {
const xhr = new XMLHttpRequest();
xhr.open("GET", `/download/${filename}`, true);
xhr.responseType = "blob";
xhr.onprogress = function (event) {
if (event.lengthComputable) {
let percent = (event.loaded / event.total) * 100;
document.getElementById('bar').style.width = percent + "%";
}
};
xhr.onload = function () {
const blob = new Blob([xhr.response]);
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = filename;
link.click();
};
xhr.send();
}
</script>

Wrapping Up

By combining Laravel with Livewire and Alpine.js, you can turn boring upload/download buttons into interactive, real-time experiences. Here’s what we’ve built:

✅ File Upload with Live Progress Bar
✅ Download Function with Visual Feedback
✅ A much better experience for your users

You don’t need to build massive UI frameworks to get professional results — just a few lines of reactive code can do wonders.

Learn more Build Upload & Download Features in Laravel with a Progress Bar

Leave a Reply