Filament Plugins

Purchase

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:

php
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:

php
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:

app/Models/YourModel.php
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:

php
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:

php
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:

php
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:

php
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:

php
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:

php
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.

php
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:

php
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:

php
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.

You can customize the width of the MediaPicker modal using the ->mediaPickerModalWidth() method on the plugin:

app/Providers/Filament/YourPanelProvider.php
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:

php
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:

php
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:

php
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:

php
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:

php
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:

php
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:

php
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:

1

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:

terminal
php artisan make:migration create_post_media_library_item_table

In the migration, define the pivot table structure:

php
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:

terminal
php artisan migrate
2

Define relationship

Next, add the relationship method to your model.

For a BelongsTo relationship (single media library item):

app/Models/Post.php
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):

app/Models/Post.php
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:

app/Models/Post.php
public function images(): BelongsToMany
{
    return $this->belongsToMany(
        MediaLibraryItem::class,
        'post_media_library_item'
    );
}
3

Using the relationship

Finally, configure the MediaPicker to use the relationship using the ->relationship() method:

For a BelongsTo relationship:

app/Filament/Admin/Resources/PostResource.php
MediaPicker::make('featuredImage')
    ->label('Featured image')
    ->relationship('featuredImage')
    ->required()

For a BelongsToMany relationship:

app/Filament/Admin/Resources/PostResource.php
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.

© FilamentPlugins.com ✦ 2022 – 2026
PrivacyTerms & Conditions
All rights reserved.