Media Library - v1.0-beta1
Livewire Components
The Media Library includes three powerful Livewire components for managing and selecting media in your application UI.
Media Modal Component
A reusable modal component for selecting media with support for single/multi-select and contextawareness for multiple instances on the same page.
Basic Usage
{{-- Include the modal component --}}
<livewire:media::media-modal
:multi-select="false"
context="profile-photo"
wire:key="profile-photo-modal"
/>
{{-- Button to trigger modal --}}
<button wire:click="$dispatch('open-media-modal', { context: 'profile-photo' })">
Select Photo
</button>
Component Properties
multi-select(boolean) - Enable multiple selectionmax-selections(int) - Maximum selections (0 = unlimited)context(string) - Unique identifier for this modal instanceselected-media(array) - Pre-selected media IDs
Events
Opening the Modal
Dispatch the open-media-modal event with context:
<button wire:click="$dispatch('open-media-modal', { context: 'site-logo' })">
Select Logo
</button>
Listening for Selection
Listen for the media-selected event:
@script
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('media-selected', (event) => {
if (event.context === 'profile-photo') {
console.log('Selected media:', event.media);
$wire.set('photoId', event.media[0].id);
}
});
});
</script>
@endscript
Single Select Example
<div>
{{-- Display current image --}}
@if ($form['siteLogo'])
<img src="{{ apGetMediaUrl($form['siteLogo'], 'thumbnail') }}" alt="Site Logo">
<button wire:click="removeLogo">Remove</button>
@endif
{{-- Select button --}}
<button wire:click="$dispatch('open-media-modal', { context: 'site-logo' })">
Select Logo
</button>
{{-- Modal --}}
<livewire:media::media-modal
:multi-select="false"
context="site-logo"
wire:key="site-logo-modal"
/>
</div>
@script
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('media-selected', (event) => {
if (event.context === 'site-logo') {
$wire.set('form.siteLogo', event.media[0].id);
}
});
});
</script>
@endscript
Multi-Select Example
<div>
{{-- Display selected images --}}
@if (count($selectedImages) > 0)
<div class="grid grid-cols-4 gap-4">
@foreach($selectedImages as $imageId)
<img src="{{ apGetMediaUrl($imageId, 'thumbnail') }}" alt="">
@endforeach
</div>
@endif
{{-- Select button --}}
<button wire:click="$dispatch('open-media-modal', { context: 'gallery' })">
Select Images (Max 10)
</button>
{{-- Modal --}}
<livewire:media::media-modal
:multi-select="true"
:max-selections="10"
context="gallery"
wire:key="gallery-modal"
/>
</div>
@script
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('media-selected', (event) => {
if (event.context === 'gallery') {
$wire.set('selectedImages', event.media.map(m => m.id));
}
});
});
</script>
@endscript
Multiple Modals on Same Page
Use different contexts to distinguish between modals:
{{-- Logo Modal --}}
<livewire:media::media-modal
:multi-select="false"
context="site-logo"
wire:key="logo-modal"
/>
{{-- Background Modal --}}
<livewire:media::media-modal
:multi-select="false"
context="background-image"
wire:key="background-modal"
/>
{{-- Triggers --}}
<button wire:click="$dispatch('open-media-modal', { context: 'site-logo' })">
Select Logo
</button>
<button wire:click="$dispatch('open-media-modal', { context: 'background-image' })">
Select Background
</button>
@script
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('media-selected', (event) => {
if (event.context === 'site-logo') {
$wire.set('form.siteLogo', event.media[0].id);
} else if (event.context === 'background-image') {
$wire.set('form.backgroundImage', event.media[0].id);
}
});
});
</script>
@endscript
Pre-selecting Media
Pass pre-selected media IDs to the modal:
<livewire:media::media-modal
:multi-select="true"
:selected-media="$existingMediaIds"
context="existing-gallery"
wire:key="existing-gallery-modal"
/>
Media Library Component
A full-featured media browsing interface with folders, tags, search, and filtering.
Basic Usage
<livewire:media::media-library />
Features
- Browse media by folder
- Search by title or filename
- Filter by type (image, video, audio, document)
- Filter by tag
- Sort by date, name, or size
- Pagination
- Grid/list view toggle
- Bulk actions
Embedding in Admin Pages
use Livewire\Volt\Volt;
// Register as admin page
Volt::route('/admin/media', MediaLibrary::class)
->middleware(['auth', 'verified']);
Media Upload Component
A drag-and-drop upload interface with progress tracking.
Basic Usage
<livewire:media::media-upload />
Features
- Drag and drop file upload
- Multi-file upload
- Upload progress bars
- File validation
- Automatic folder selection
- Tag assignment
- Metadata input
Custom Upload Form
<form wire:submit.prevent="upload">
<input type="file" wire:model="files" multiple>
@error('files.*')
<span class="error">{{ $message }}</span>
@enderror
<select wire:model="folderId">
<option value="">Root</option>
@foreach ($folders as $folder)
<option value="{{ $folder->id }}">{{ $folder->fullPath() }}</option>
@endforeach
</select>
<button type="submit">Upload</button>
</form>
<div wire:loading wire:target="files">
Uploading...
</div>
Component Events
Global Events
All components emit and listen for these events:
media-uploaded- Fired when new media is uploadedmedia-updated- Fired when media metadata is updatedmedia-deleted- Fired when media is deletedfolder-created- Fired when a new folder is createdfolder-updated- Fired when a folder is updated
Listening to Events
@script
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('media-uploaded', (event) => {
console.log('New media uploaded:', event.media);
// Refresh your component
$wire.$refresh();
});
Livewire.on('media-deleted', (event) => {
console.log('Media deleted:', event.mediaId);
// Update UI
});
});
</script>
@endscript
Customizing Components
Publishing Views
Publish the component views to customize:
php artisan vendor:publish --tag=media-views
Views will be in resources/views/vendor/media/livewire/.
Extending Components
Create your own component that extends the base:
namespace App\Livewire;
use ArtisanPackUI\MediaLibrary\Livewire\Components\MediaModal as BaseMediaModal;
class CustomMediaModal extends BaseMediaModal
{
public function mount(bool $multiSelect = false, int $maxSelections = 0, array $selectedMedia = [], string $context = ''): void
{
parent::mount($multiSelect, $maxSelections, $selectedMedia, $context);
// Add custom logic
$this->customProperty = 'custom value';
}
public function customMethod()
{
// Custom functionality
}
}
Best Practices
Always Use Context
When using multiple modals, always provide unique contexts:
{{-- Good --}}
<livewire:media::media-modal context="logo" wire:key="logo-modal" />
<livewire:media::media-modal context="banner" wire:key="banner-modal" />
{{-- Bad (modals will conflict) --}}
<livewire:media::media-modal />
<livewire:media::media-modal />
Use wire:key
Always provide a unique wire:key to prevent Livewire conflicts:
<livewire:media::media-modal context="photo" wire:key="photo-modal-{{ $userId }}" />
Handle Errors
Always handle potential errors in event listeners:
Livewire.on('media-selected', (event) => {
try {
if (event.context === 'profile-photo' && event.media.length > 0) {
$wire.set('photoId', event.media[0].id);
}
} catch (error) {
console.error('Error handling media selection:', error);
}
});
Next Steps
- Review API Endpoints for programmatic access
- Explore Customization options
- Learn about Permissions