Image Library

This component manages multiple image upload and is powered by Livewire`s file upload, including all features like file size/type validation and automatic storage persistence on local and S3 disks.

If you need a native file upload or want to handle only one image see the File component.
If you need to nicely display images see Image Gallery component.


Add images
Max 100Kb
$files = $this->files;
$library = $this->library;
$user = $this->user;
wire:model="files" {{-- Temprary files --}}
wire:library="library" {{-- Library metadata property --}}
:preview="$library" {{-- Preview control --}}
label="Product images"
hint="Max 100Kb" />


First, add Cropper.js and Sortable.js.

{{-- Cropper.js --}}
<script src=""></script>
<link rel="stylesheet" href="" />
{{-- Sortable.js --}}
<script src=""></script>

Add a new json column on your migration files to represent the image library metadata.

// Users table migration

Cast that column as AsCollection.

// User model
protected $casts = [
'library' => AsCollection::class,


The following example considers that you named it as library and you are editing an existing user.

use Livewire\WithFileUploads;
use Mary\Traits\WithMediaSync;
use Illuminate\Support\Collection;
class extends Component {
// Add these Traits
use WithFileUploads, WithMediaSync;
// Temporary files
#[Rule(['files.*' => 'image|max:1024'])]
public array $files = [];
// Library metadata (optional validation)
public Collection $library;
// Editing this user
public User $user;
public function mount(): void
// Load existing library metadata from your model
$this->library = $this->user->library;
// Or ... an empty collection if this component creates a user
// $this->library = new Collection()
public function save(): void
// Your stuff ...
// Sync files and updates library metadata
// Or ... first create the user, if this component creates a user
// $user = User::create([...]);
// $this->syncMedia($user);

S3 storage

Make sure to proper configure CDN CORS on your S3 provider, by listing your local and production environment addresses. Otherwise, cropper won't work.

Sync options

If you are using default variable names described on "Setup" and "Example" topics above, you are good to go. Otherwise, here are all options for syncing media on storage.

model: $this->user, // A model that has an image library
library: 'library', // The library metadata property on component
files: 'files', // Temp files property on component
storage_subpath: '', // Sub path on storage. Ex: '/users'
model_field: 'library', // The model column that represents the library metadata
visibility: 'public' // Visibility on storage
disk: 'public' // Storage disk. Also works with 's3'


Here are all default labels.

crop-title-text="Crop image"
add-files-text="Add images" />

Cropper settings

You can set or override any Cropper.js option.

$config = [ 'guides' => false ];
<x-image-library ... :crop-config="$config" />

Once Cropper.js does not offer an easy way to customize its CSS, just inspect browser console to hack the CSS that works best for you. We are using the following on this page.

.cropper-point {
width: 10px !important;
height: 10px !important;