Currently Available: Need a skilled Software Developer for your next project?
Categories
Laravel

How to Upload Images with Validation and Previews in Laravel Livewire

When someone uploads an image on a Laravel page, Livewire sends the selected file from the file input to a PHP component. Livewire first puts the file in temporary storage, which holds it until the component saves it permanently. The page can use that temporary file to show a preview and validate the image before the reader submits the form.

The example uses Livewire’s WithFileUploads trait, Laravel validation rules, and the uploaded file’s temporaryUrl() method, which creates a temporary link for the preview. It validates one image and stores it on Laravel’s public disk. A Livewire component is the PHP class that handles a page’s interactions; its view contains the form.

Add the upload property and validation

Add WithFileUploads to the component, then connect the file input to a public property with wire:model. Livewire transfers the selected file to temporary storage and assigns that property an object representing the temporary uploaded file. The Livewire upload documentation describes this upload flow and the methods available for the temporary file.

<?php

namespace App\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;

class ImageUpload extends Component
{
    use WithFileUploads;

    public $photo;

    protected $rules = [
        'photo' => 'required|image|max:1024',
    ];

    public function updatedPhoto(): void
    {
        $this->validateOnly('photo');
    }

    public function save(): void
    {
        $this->validate();

        $path = $this->photo->store('photos', 'public');

        // Save $path on the relevant database record.

        $this->reset('photo');
    }

    public function render()
    {
        return view('livewire.image-upload');
    }
}

The image rule checks that the upload is an image. The max:1024 rule limits it to 1,024 kilobytes, or 1 MB. Livewire uses Laravel’s standard validation rules, as shown in its file upload validation examples.

The updatedPhoto() method validates the image as soon as Livewire updates the property. In save(), $this->validate() checks the image again before storing it. Keep this server-side check even when the file input has browser restrictions, because a request can bypass those page controls.

Show the temporary preview

Call temporaryUrl() on the uploaded file to show its preview before saving it permanently. The method returns a temporary signed URL, a link that provides temporary access to the image.

<form wire:submit="save">
    <label for="photo">Choose an image</label>
    <input
        id="photo"
        type="file"
        wire:model="photo"
        accept="image/*"
    >

    <div wire:loading wire:target="photo">
        Uploading image...
    </div>

    @error('photo')
        <p>{{ $message }}</p>
    @enderror

    @if ($photo && ! $errors->has('photo') && $photo->isPreviewable())
        <img
            src="{{ $photo->temporaryUrl() }}"
            alt="Preview of the selected image"
            style="max-width: 320px"
        >
    @endif

    <button type="submit">Save image</button>
</form>

The browser’s accept attribute filters the choices shown in the file chooser. Laravel’s validation rules determine which files the server accepts. Livewire supports temporaryUrl() for image uploads. In Livewire 4, livewire.temporary_file_upload.preview_mimes controls which file types can have preview URLs. Its defaults also include audio and video formats. temporaryUrl() throws an exception for unsupported files, so check isPreviewable() before calling it.

If the preview request returns a 401 error, check the temporary-upload settings and storage URL for the Livewire version and storage disk you use. A Livewire discussion about preview 401 errors describes this behavior in one specific configuration.

Store the validated image

The store('photos', 'public') call saves the validated image in the photos directory on Laravel’s public disk and returns its path. Save that path in the relevant database record if the code needs to retrieve the image later. To keep the image private, choose a different disk or visibility setting. Laravel’s storage API supports both choices.

Livewire keeps the temporary upload separate from the permanent file. The save() method stores the image in the chosen location after validation succeeds. It then clears the component property, which removes the old preview.

Accept several images

To upload several images, make the component property an array. The photos.* wildcard rule applies validation to each file in that array:

public $photos = [];

protected $rules = [
    'photos' => 'array',
    'photos.*' => 'image|max:1024',
];

Add multiple to the file input and bind it to photos:

<input id="photos" type="file" wire:model="photos" multiple>

@error('photos.*')
    <p>{{ $message }}</p>
@enderror

@foreach ($photos as $photo)
    @if (! $errors->has('photos.' . $loop->index) && $photo->isPreviewable())
        <img src="{{ $photo->temporaryUrl() }}" alt="Preview of a selected image">
    @endif
@endforeach

In the save method, validate the array, then store each file separately:

$this->validate();

$paths = [];

foreach ($this->photos as $photo) {
    $paths[] = $photo->store('photos', 'public');
}

Use the resulting paths to update the records for those images. The per-file rule rejects any invalid image, even when the reader selects several files at once.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *