Form Upload Async
Asynchronous form upload component.
Upload Async, Customization Blocks
TallStackUI v4 introduces a new and extremely useful component for file uploads: upload.async . Asynchronous uploading splits the file into smaller parts, allowing you to upload large files without changing the default PHP settings. The main difference between upload and upload.async is how the file is sent. While upload is good for simplifying and speeding up file uploads, it requires some changes to the default PHP settings to allow large files. upload.async , on the other hand, allows uploading large files without necessarily changing anything in PHP, but requires a bit more code to work.
The route prop accepts a named route or a plain URL. Either wire:model or name is required.
With upload.async , the selected file is divided into chunks. Each chunk is sent to the backend as an individual POST request. To process them, you need to create a Laravel controller with an upload method, use the TallStackUI upload trait, and point a route to the controller. Here is a basic example:
use Illuminate\Http\Request;use TallStackUi\Http\AsyncUpload\Uploader; class UploadController{ use Uploader; public function store(Request $request) { return $this->upload($request, [ 'disk' => 'public', 'directory' => 'posts/attachments', 'rules' => ['file' => ['mimes:jpg,png,pdf']], ]); }}
// routes/web.php use Illuminate\Support\Facades\Route;use App\Http\Controllers\UploadController; Route::post('/files/upload', [ UploadController::class, 'store'])->name('files.upload');
Finally, you can use the component:
<x-upload.async :route="route('files.upload')" label="Document" />
Before continuing, it is important to know:
- The component can be used outside Livewire components.
- You need to use a wire:model or name (outside Livewire components) to receive the uploaded file.
- Without a wire:model or name , the component will throw an exception.
- When the file is successfully uploaded, you will receive an array of data that represents the file:
[ 'id' => '9f1c...-uuid', 'path' => 'posts/attachments/8ad2....pdf', 'real_name' => 'contract.pdf', 'size' => 184320, 'mime' => 'application/pdf', 'url' => 'http://app.test/storage/posts/attachments/8ad2....pdf',]
Drop files here
or click to select
Bound value: null
<x-upload.async :route="route('files.upload')" label="Document" />
Drop files here
or click to select
<x-upload.async :route="route('files.upload')" label="Gallery" accept="application/pdf" multiple :limit="6" :columns="4" :max-size="60" />
An option to stage the files and wait for the send button.
Drop files here
or click to select
<x-upload.async :route="route('files.upload')" label="Files" accept="application/pdf" multiple manual :max-size="60"> <x-slot:footer> <div x-show="files.length" class="mt-3 flex items-center justify-between"> <span x-text="summary()" class="text-xs text-gray-500"></span> <div class="flex items-center gap-2"> <x-button color="red" x-on:click="clear()" round sm>Abort & Clear</x-button> <x-button x-bind:disabled="!sendable() || disabled" x-on:click="send()" round>Upload Now</x-button> </div> </div> </x-slot:footer></x-upload.async>
All options of the upload method.
As you may have noticed, implementing async upload is relatively simple:
use Illuminate\Http\Request;use TallStackUi\Http\AsyncUpload\Uploader; class UploadController{ use Uploader; public function store(Request $request) { return $this->upload($request, [ 'disk' => 'public', 'directory' => 'posts/attachments', 'rules' => ['file' => ['mimes:jpg,png,pdf']], ]); }}
However, the upload method has several useful options:
You can use store to control how the file is persisted after a complete upload. This runs only once when the file is fully uploaded successfully.
return $this->upload($request, [ 'disk' => 'public', 'store' => fn (SplFileInfo $file, AsyncUploadRequest $request): string => $post ->addMedia($file) ->usingFileName($request->input('real_name')) ->toMediaCollection('attachments') ->getPathRelativeToRoot(),]);
Without store , the file is persisted based on the directory . Without either of them, the component will throw an AsyncUploadException .
Chunks are written to individual part files by index, then combined when the upload is complete. Since concurrency controls how many chunks upload at once, they can arrive in any order. Storing each chunk separately avoids interleaved data and lets the handler detect completion by counting files.
Coordination relies on atomic directory creation and renaming. Directory creation determines which request fires AsyncUploadStarted , while the rename determines which request performs finalization. A file count cannot provide this guarantee because two requests may detect completion at the same time.
An option to clean up old temporary upload files.
// routes/console.php Schedule::command('tallstackui:async-upload:clear')->daily();
<x-upload.async :route="route('files.upload')" x-on:added="console.log($event.detail.file)" x-on:progress="console.log($event.detail.progress)" x-on:success="console.log($event.detail.file)" x-on:error="console.log($event.detail.error)" x-on:complete="console.log($event.detail.files)" />
There are many configuration options that you can control globally via the configuration file.