---
url: /guide/picker-field.md
description: >-
  The MediaPicker form field: single and multiple selection, file type filters,
  limits, relationship or column storage, folders, layouts and in-field uploads.
---

# Picker Field

`MediaPicker` is a Filament form field that stores a selection from the library. It opens the full library in a modal, and people can also drop, paste or upload files straight into the field.

```php
use Hoceineel\FilamentMediaLibrary\Filament\Forms\Components\MediaPicker;

MediaPicker::make('cover_id')
    ->image()
    ->aspectRatio('16:9');
```

## Single and multiple

By default the field holds one file. Call `multiple()` for a list, and limit it with `minItems()` and `maxItems()`.

```php
MediaPicker::make('cover_id')->image();

MediaPicker::make('gallery')
    ->multiple()
    ->image()
    ->minItems(1)
    ->maxItems(12)
    ->reorderable();
```

* A single image shows as a large cover with Preview, Choose another, Upload and Remove actions.
* Multiple selections show as cards or rows. Drag them to reorder, unless you call `reorderable(false)`. Reordering only applies to `multiple()` fields.
* `minItems()` and `maxItems()` only apply to `multiple()` fields. A single field always allows exactly one file.

## Restrict file types

`image()` is a shortcut for `acceptedFileTypes(['image/*'])`. Wildcards work.

```php
MediaPicker::make('brochure')
    ->acceptedFileTypes(['application/pdf', 'application/zip']);
```

The type filter limits what the picker modal shows, what the field accepts when people upload, and what the server accepts when the form is saved.

## Where the selection is stored

There are two storage modes.

**Column mode** is the default. The field stores one id, or a JSON array of ids for `multiple()`, in the attribute with the field's name. Cast array columns on the model:

```php
protected function casts(): array
{
    return ['gallery_ids' => 'array'];
}
```

```php
MediaPicker::make('cover_id')->image();
MediaPicker::make('gallery_ids')->multiple();
```

In column mode the field also records where each file is used, so the library shows "Used in" and protects the file from deletion. The usage is saved under a collection named after the field. Turn it off with `trackUsage(false)`.

**Relationship mode** syncs the `media_library_attachments` table instead and keeps the order. The model needs the `HasMediaLibrary` trait (see [Models & Blade](/guide/models-and-blade)).

```php
MediaPicker::make('gallery')
    ->relationship()
    ->multiple()
    ->maxItems(12);

MediaPicker::make('downloads')
    ->relationship('downloads')
    ->multiple()
    ->acceptedFileTypes(['application/pdf']);
```

Without an argument, `relationship()` uses the field name as the collection. Pass a name, or call `collection('downloads')`, to use another one. In relationship mode the field does not write to a column, and usage is always tracked.

Read relationship selections with `$post->getMediaLibraryItems('gallery')`. Display columns and entries pick the same collection with `collection()`: see [Table Columns](/guide/table-columns) and [Infolist Entries](/guide/infolist-entries).

## Open in a folder

```php
MediaPicker::make('downloads')
    ->folder('Downloads', lock: true);
```

`folder()` takes a folder id or the name of a root folder. A missing named folder is created when the user is allowed to create folders. New uploads from the field go into that folder.

With `lock: true`, the picker stays inside the folder.

::: warning
Locking is a convenience, not a permission boundary. Use [policies](/reference/authorization) to restrict access.
:::

## Layout and presentation

Images show as a grid of cards. Other files show as a list with type, size and dimensions. The field picks a grid when every accepted type starts with `image/`, and a list otherwise. Override it:

```php
MediaPicker::make('gallery')->multiple()->list();
MediaPicker::make('logos')->multiple()->grid();
MediaPicker::make('files')->multiple()->layout(PickerLayout::List);
```

`PickerLayout` lives in `Hoceineel\FilamentMediaLibrary\Enums`. The layout applies to `multiple()` fields.

`aspectRatio()` frames a single selection at a fixed ratio. It accepts `16:9`, `16/9` or `1`.

`conversion()` sets which size the cards show. It defaults to `thumb`. When `aspectRatio()` is set, a single cover uses the `preview` conversion so the larger frame stays sharp.

## Uploading inside the field

With `uploadable()` on (the default), people can:

* drop files onto the field,
* paste an image from the clipboard,
* press **Upload** to pick files from their device.

Files upload in chunks with live progress and are added to the field when they finish. Uploads respect the field's accepted types, the maximum file size and, for `multiple()` fields, the remaining capacity from `maxItems()`. A file that does not match is rejected in the browser with a message.

If the file already exists in the library (same checksum), the field uses the existing copy instead of storing a second one. It answers the duplicate prompt for the user. The exception is `upload.duplicates` set to `DuplicateStrategy::Allow`, which always stores a new copy.

Uploading needs the `create` policy ability and an upload route for the current page. A disabled field is never uploadable. To only allow picking existing files, call `uploadable(false)`.

## Validation

Validation always runs on the server. The field adds these rules:

* Every id must exist in the library, belong to the current tenant, be visible to the user (other people's private files are rejected), and match the accepted file types. A failure uses Laravel's `validation.exists` message.
* `minItems()` and `maxItems()` become `min` and `max` rules on `multiple()` fields.

Use Filament's own `required()` to demand a selection.

## All options

| Method | Default | Purpose |
|---|---|---|
| `multiple(bool)` | off | Hold a list of files instead of one. |
| `minItems(int)` | none | Minimum files. `multiple()` only. |
| `maxItems(int)` | none | Maximum files. `multiple()` only. |
| `image()` | | Shortcut for `acceptedFileTypes(['image/*'])`. |
| `acceptedFileTypes(array)` | all types | MIME filter. Wildcards such as `image/*` work. |
| `reorderable(bool)` | on | Drag to reorder. `multiple()` only. |
| `relationship(?string)` | off | Store selections as attachments. Needs `HasMediaLibrary`. |
| `collection(string)` | field name | Attachment collection used for usage tracking and relationship mode. |
| `trackUsage(bool)` | on | Record usage in column mode. |
| `folder(id or name, lock: bool)` | none | Open the picker in a folder, optionally locked. |
| `grid()`, `list()`, `layout(PickerLayout)` | by file types | Card grid or file list. |
| `aspectRatio(string)` | none | Fixed ratio for a single selection. |
| `conversion(string)` | `thumb` | Conversion shown on the cards. |
| `uploadable(bool)` | on | Allow drop, paste and upload in the field. |
| `previewable(bool)` | on | Show the full screen preview button. |
| `showFileNames(bool)` | on | Show the file name under each card. |
| `openOnMount(bool)` | off | Open the library as soon as the field renders. |
| `submitOnPick(bool)` | off | Submit the surrounding action modal after files are inserted. |
| `buttonLabel(string)` | "Browse library" | Text of the button that opens the library. |

`openOnMount()` and `submitOnPick()` are meant for action modals. The [rich editor plugin](/guide/rich-editor) uses both.

Most options also accept a closure, so you can compute them from the form state or the current record.
