Getting started
Library
Components
Integrations
Media Picker
In order to select items from your Media Library, the packages provides a custom Filament form field called MediaPicker. This field can be used in any Filament form, both inside or outside a Filament panel.
The field consists of two parts: first, when you have items selectedwhen the collection has files, it will display them in your form. Second, it provides a modal to open when the user wants to select or upload items to the media librarymanage the collection.
Using the field
You can include the field like this:
use RalphJSmit\Filament\MediaLibrary\Filament\Forms\Components\MediaPicker;
MediaPicker::make('featured_image_id')
->label('Choose image')
->required()
use RalphJSmit\Filament\MediaLibrary\Filament\Forms\Components\MediaPicker;
MediaPicker::make('featured_image_collection')
->label('Featured image collection')
->helperText('Add, edit and delete images from the featured image collection.')
->required()
use RalphJSmit\Filament\MediaLibrary\Filament\Forms\Components\MediaPicker;
MediaPicker::make('featured_image_path')
->label('Choose image')
->required()
The value of the field will be the id of the related MediaLibraryItem. See the driver overview for more information about how this driver stores data.
The value of the field will be a file path string relative to the configured disk. See the driver overview for more information about how this driver stores data.
With the Spatie driver, the MediaPicker acts as a collection manager – the field name corresponds to the Spatie media collection name and the field manages that collection directly on the model. Nothing is dehydrated into the form's data array, so the field doesn't need to be present as a column on the model. See the driver overview for more information.
Selecting multiple files
To select multiple files, you can use the ->multiple() method:
MediaPicker::make('image_ids')
->label('Choose images')
->multiple()
->required()
MediaPicker::make('image_paths')
->label('Choose images')
->multiple()
->required()
If you are storing the keys as an JSON array on your model, you will need to add an array or collection cast to the field in your model:
protected $casts = [
'image_ids' => 'array',
];
Minimum or maximum files
You can require a minimum or maximum number of files to be selected using the ->minFiles() and ->maxFiles() methods:
MediaPicker::make('image_ids')
->label('Select between 2-5 files for your header gallery')
->multiple()
->minFiles(2)
->maxFiles(5)
// Optional, override custom validation message:
->validationMessages([
'min' => 'Please select at least 2 brochures.',
'max' => 'Please select maximum 5 brochures.',
])
MediaPicker::make('image_paths')
->label('Select between 2-5 files for your header gallery')
->multiple()
->minFiles(2)
->maxFiles(5)
// Optional, override custom validation message:
->validationMessages([
'min' => 'Please select at least 2 brochures.',
'max' => 'Please select maximum 5 brochures.',
])
Limiting file types
You can limit the file types the user can select using the ->acceptedFileTypes() method:
You can limit the collection to a subset of file types by using the ->acceptedFileTypes() method:
MediaPicker::make('document_ids')
->label('Choose documents')
->multiple()
->acceptedFileTypes(['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
->required()
MediaPicker::make('documents_collection')
->label('Manage documents')
->multiple()
->acceptedFileTypes(['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
->required()
MediaPicker::make('document_paths')
->label('Choose documents')
->multiple()
->acceptedFileTypes(['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'])
->required()
Please note that this will only limit the selection of files in the media picker. It will not prevent users from uploading other file types to the media library itself. If you would like to prevent that, please look into defining upload constraints.
Uploading new files into the collection will be limited to the defined mimetypes. Pre-existing files from the collection will not be impacted or shown.
If you would like to provide a custom validation message, you can use the ->validationMessages() function:
MediaPicker::make('brochure_id')
->label('Choose brochure')
->acceptedFileTypes(['application/pdf'])
// Optional, override custom validation message:
->validationMessages([
'accepted_file_types' => 'Brochures can only be PDFs.',
])
MediaPicker::make('brochure_path')
->label('Choose brochure')
->acceptedFileTypes(['application/pdf'])
// Optional, override custom validation message:
->validationMessages([
'accepted_file_types' => 'Brochures can only be PDFs.',
])
Selection action & modal
Modifying the select action
To modify the select action that opens the Media Picker modal, you can use the following methods:
MediaPicker::make('image_id')
->label('Choose image')
->selectMediaActionLabel('Select image')
->selectMediaActionColor('primary')
->selectMediaActionIcon(Heroicon::OutlinedPlus)
->modifySelectMediaActionIcon(function (SelectMediaAction $action) {
// ...
})
MediaPicker::make('image_collection')
->label('Manage files')
->selectMediaActionColor('primary')
->selectMediaActionIcon(Heroicon::OutlinedPlus)
->modifySelectMediaActionIcon(function (SelectMediaAction $action) {
// ...
})
MediaPicker::make('image_path')
->label('Choose image')
->selectMediaActionLabel('Select image')
->selectMediaActionColor('primary')
->selectMediaActionIcon(Heroicon::OutlinedPlus)
->modifySelectMediaActionIcon(function (SelectMediaAction $action) {
// ...
})
Scoping to folder
By default, the MediaPicker will open in the root folder. However, in some cases, you might want to only allow your users to select/upload images from and to specific folders. You can do that using the ->scopedFolder() function. This forces a specific folder to allow your users to create and select from (e.g. go down in hierarchy), but not to open up parent folders or go up in the hierarchy.
To scope the Media Picker to a specific folder, you can use the ->scopedFolder() method:
use RalphJSmit\Filament\Explore\Filament\MediaLibrary\MediaLibraryFolder;
use RalphJSmit\Filament\Explore\Drivers\FilesystemStorageDriver\FileData;
use RalphJSmit\Filament\Explore\Enums\FileType;
MediaPicker::make('featured_image_id')
->scopedFolder(MediaLibraryFolder::find(99))
use RalphJSmit\Filament\Explore\Filament\MediaLibrary\MediaLibraryFolder;
use RalphJSmit\Filament\Explore\Drivers\FilesystemStorageDriver\FileData;
use RalphJSmit\Filament\Explore\Enums\FileType;
MediaPicker::make('featured_image_path')
->scopedFolder(FileData::fromDisk('s3', 'path/to/folder', FileType::Folder))
Using a closure:
MediaPicker::make('featured_image_id')
->scopedFolder(fn (Event $record) => $record->mediaLibraryFolder)
MediaPicker::make('featured_image_path')
->scopedFolder(fn (Event $record) => FileData::fromDisk('s3', "events/{$record->getKey()}", FileType::Folder))
Default folder
If you don't want to force your users to use a specific folder, but only nudge them, you can also use the ->defaultFolder() method. This method allows you to specify a default folder that the MediaPicker will open in. The difference with ->folder() is that this method will allow your users to open other folders as well, also higher in the hierarchy.
The defaultFolder() functions accepts a MediaLibraryFolder or FileData object as parameter. You can also pass a closure, and use that closure to retrieve the folder dynamically from e.g. the current record.
use RalphJSmit\Filament\Explore\Filament\MediaLibrary\MediaLibraryFolder;
use RalphJSmit\Filament\Explore\Drivers\FilesystemStorageDriver\FileData;
use RalphJSmit\Filament\Explore\Enums\FileType;
MediaPicker::make('featured_image_id')
->defaultFolder(MediaLibraryFolder::find(99))
use RalphJSmit\Filament\Explore\Filament\MediaLibrary\MediaLibraryFolder;
use RalphJSmit\Filament\Explore\Drivers\FilesystemStorageDriver\FileData;
use RalphJSmit\Filament\Explore\Enums\FileType;
MediaPicker::make('featured_image_path')
->defaultFolder(FileData::fromDisk('s3', 'path/to/folder', FileType::Folder))
Using a closure:
MediaPicker::make('featured_image_id')
->defaultFolder(fn (Event $record) => $record->mediaLibraryFolder)
MediaPicker::make('featured_image_path')
->defaultFolder(fn (Event $record) => FileData::fromDisk('s3', "events/{$record->getKey()}", FileType::Folder))
Note: please note that the media picker will now open this folder by default. However, users are still able to click to other folders and view them. If you have a need to disable this and only force a specific folder, please use the
->scopedFolder()method (see above).
Individual file info on multiple selection
By default, when a user is allowed to select one file, the modal with open the Media Library including the file-info sidebar at the right. When the user is allowed to select multiple files, the sidebar will not be shown by default as that can be confusing to the user. However, if you still wish to enable this, you can use the ->fileInfoMultipleFileSelection() method:
MediaPicker::make('image_ids')
->label('Choose images')
->multiple()
->fileInfoMultipleFileSelection()
MediaPicker::make('image_paths')
->label('Choose images')
->multiple()
->fileInfoMultipleFileSelection()
This will enable both the bulk-selection checkboxes as well as the file-info sidebar when selecting multiple files.
Modal width
You can customize the width of the MediaPicker modal using the ->mediaPickerModalWidth() method on the plugin:
use Filament\Support\Enums\Width;
$plugin->mediaPickerModalWidth(Width::SevenExtraLarge)
Selected items
Reordering
You can allow your users to reorder the selected itemscollection using the ->reorderable() method:
MediaPicker::make('image_ids')
->label('Choose images')
->multiple()
->reorderable()
->required()
MediaPicker::make('images_collection')
->label('Manage images')
->multiple()
->reorderable()
->required()
MediaPicker::make('image_paths')
->label('Choose images')
->multiple()
->reorderable()
->required()
If a user hovers over an image, the cursor will change into a "move" icon, so that it is clear that the media can be reordered.
Reordering with a relationship
By default, reordering items in a relationship MediaPicker is disabled. This is because your pivot table needs an order column to store the order of related records. To enable reordering, you may use the ->orderColumn() method, passing in the name of the column on your pivot table to store the order in:
MediaPicker::make('images')
->label('Gallery images')
->relationship('images')
->multiple()
->orderColumn('order_column')
Pivot data
When using a BelongsToMany relationship, you can store additional data on the pivot table using the ->pivotData() method:
MediaPicker::make('images')
->label('Gallery images')
->relationship('images')
->multiple()
->pivotData(['added_by' => auth()->id()])
You can also pass a closure to resolve pivot data dynamically:
MediaPicker::make('images')
->relationship('images')
->multiple()
->pivotData(fn () => ['added_by' => auth()->id()])
Downloading
You can allow your users to download the selected items using the ->downloadable() method:
MediaPicker::make('image_id')
->label('Featured image')
->downloadable()
MediaPicker::make('image_collection')
->label('Featured image')
->downloadable()
MediaPicker::make('image_path')
->label('Featured image')
->downloadable()
Actions
You can add additional actions to each selected itemfile in the collection using the ->fileActions() method:
use RalphJSmit\Filament\Explore\Filament\Actions\RenameAction;
MediaPicker::make('image_ids')
->label('Choose images')
->multiple()
->fileActions([
RenameAction::make(),
Action::make('optimize')
->icon(Heroicon::OutlinedSparkles)
->action(function (MediaLibraryItem $file) {
// Perform an action...
}),
])
use RalphJSmit\Filament\Explore\Filament\Actions\RenameAction;
MediaPicker::make('images_collection')
->label('Manage images')
->multiple()
->fileActions([
RenameAction::make(),
Action::make('optimize')
->icon(Heroicon::OutlinedSparkles)
->action(function (MediaLibraryItem $file) {
// Perform an action...
}),
])
use RalphJSmit\Filament\Explore\Filament\Actions\RenameAction;
MediaPicker::make('image_paths')
->label('Choose images')
->multiple()
->fileActions([
RenameAction::make(),
Action::make('optimize')
->icon(Heroicon::OutlinedSparkles)
->action(function (MediaLibraryItem $file) {
// Perform an action...
}),
])
This will display the actions together with the download and/or delete action.
Bulk actions
You can allow your users to perform bulk actions on the selected itemsfiles in the collection in your field. This is very handy to let the user batch-process an already selected set ofthe files.
To enable bulk selection & actions, use the ->bulkSelectable() method:
use RalphJSmit\Filament\Explore\Filament\Actions\BulkAction;
MediaPicker::make('image_ids')
->label('Choose images')
->multiple()
->bulkSelectable()
->bulkActions([
BulkAction::make('optimize')
->icon(Heroicon::OutlinedSparkles)
->action(function (Collection $files) {
// Perform an action...
}),
])
use RalphJSmit\Filament\Explore\Filament\Actions\BulkAction;
MediaPicker::make('images_collection')
->label('Manage images')
->multiple()
->bulkSelectable()
->bulkActions([
BulkAction::make('optimize')
->icon(Heroicon::OutlinedSparkles)
->action(function (Collection $files) {
// Perform an action...
}),
])
use RalphJSmit\Filament\Explore\Filament\Actions\BulkAction;
MediaPicker::make('image_paths')
->label('Choose images')
->multiple()
->bulkSelectable()
->bulkActions([
BulkAction::make('optimize')
->icon(Heroicon::OutlinedSparkles)
->action(function (Collection $files) {
// Perform an action...
}),
])
Relationship support
You can integrate the MediaPicker with a BelongsTo or BelongsToMany relationship on your model. This is useful when you want to store the relationship between your model and media library items in a proper database relationship instead of storing IDs directly in a column.
The MediaPicker supports both relationship types:
- BelongsTo: For single media library items
- BelongsToMany: For multiple media library items
To integrate a relationship, follow the steps below:
Create the pivot table (BelongsToMany only)
If you're using a BelongsToMany relationship, you'll need to create a pivot table. Skip this step if you're using a BelongsTo relationship.
Create a migration for your pivot table:
php artisan make:migration create_post_media_library_item_table
In the migration, define the pivot table structure:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('media_library_item_post', function (Blueprint $table) {
$table->id();
$table->foreignId('post_id')->constrained()->cascadeOnDelete();
$table->foreignId('media_library_item_id')->constrained()->cascadeOnDelete();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('media_library_item_post');
}
};
Run the migration:
php artisan migrate
Define relationship
Next, add the relationship method to your model.
For a BelongsTo relationship (single media library item):
use RalphJSmit\Filament\MediaLibrary\Models\MediaLibraryItem;
class Post extends Model
{
public function featuredImage(): BelongsTo
{
return $this->belongsTo(MediaLibraryItem::class, 'featured_image_id');
}
}
For a BelongsToMany relationship (multiple media library items):
use RalphJSmit\Filament\MediaLibrary\Models\MediaLibraryItem;
class Post extends Model
{
public function images(): BelongsToMany
{
return $this->belongsToMany(MediaLibraryItem::class);
}
}
If your pivot table doesn't follow Laravel's naming convention, specify it explicitly:
public function images(): BelongsToMany
{
return $this->belongsToMany(
MediaLibraryItem::class,
'post_media_library_item'
);
}
Using the relationship
Finally, configure the MediaPicker to use the relationship using the ->relationship() method:
For a BelongsTo relationship:
MediaPicker::make('featuredImage')
->label('Featured image')
->relationship('featuredImage')
->required()
For a BelongsToMany relationship:
MediaPicker::make('images')
->label('Gallery images')
->relationship('images')
->multiple()
->required()
When using relationships, the MediaPicker will automatically manage the relationship records when the form is saved. You don't need to manually handle the saving of the relationship data.