> ## Documentation Index
> Fetch the complete documentation index at: https://flex-fields.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# FlexFileUpload & FlexImageUpload

<img src="https://mintcdn.com/flex-fields/AtYa9gTYnesC_HJb/art/sc-31.png?fit=max&auto=format&n=AtYa9gTYnesC_HJb&q=85&s=4eaab72ddd7c48f9973682c2793e5a04" alt="FlexFileUpload" width="2752" height="1536" data-path="art/sc-31.png" />

[← Back to Table of Contents](/docs/index)

### Summary

Styled Filament file upload with security defaults, MIME presets, upload summaries, optional metadata sidecars, image optimization hooks, scoped per-user directories, and opt-in **webcam capture** / **URL import** tabs *(v2.6.1)*.

|                     |                                                                                                                           |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| **FlexFileUpload**  | `Bjanczak\FilamentFlexFields\Filament\Forms\Components\FlexFileUpload`                                                    |
| **FlexImageUpload** | `Bjanczak\FilamentFlexFields\Filament\Forms\Components\FlexImageUpload` (extends `FlexFileUpload`, `imagesOnly()` preset) |
| **State type**      | `string\|array\|null` — stored path(s) on disk                                                                            |
| **FieldType**       | `file` → `FlexFileUpload`, `image` → `FlexImageUpload`                                                                    |
| **Extends**         | `Filament\Forms\Components\FileUpload`                                                                                    |

### Basic usage

#### Avatar (image)

```php theme={null}
use Bjanczak\FilamentFlexFields\Filament\Forms\Components\FlexImageUpload;

FlexImageUpload::make('avatar')
    ->label('Profile photo')
    ->withRecommendedDefaults()
    ->avatar()
    ->imageEditor()
    ->circleCropper()
    ->disk('public')
    ->directory('avatars')
    ->maxFiles(1)
    ->optimizeImages()
    ->maxImageWidth(512)
    ->maxImageHeight(512);
```

#### Single document

```php theme={null}
use Bjanczak\FilamentFlexFields\Filament\Forms\Components\FlexFileUpload;

FlexFileUpload::make('contract')
    ->label('Contract PDF')
    ->withRecommendedDefaults()
    ->documentsOnly()
    ->disk('local')
    ->directory('contracts')
    ->maxFiles(1)
    ->showFileIcon()
    ->uploadSummary()
    ->requireReplaceConfirmation();
```

#### Multiple files with total size guard

```php theme={null}
FlexFileUpload::make('attachments')
    ->withRecommendedDefaults()
    ->multiple()
    ->maxFiles(5)
    ->maxTotalSizeKb(10240)
    ->remainingSlotsLabel()
    ->uploadSummary()
    ->disk('local')
    ->directory('inquiries/attachments');
```

#### Metadata sidecar

Stores original filename, MIME, size, and image dimensions in a sibling state path:

```php theme={null}
FlexFileUpload::make('scan')
    ->withRecommendedDefaults()
    ->storeMetadataIn('scan_meta')
    ->disk('local')
    ->directory('scans');
// $data['scan_meta'] => ['original_name' => '...', 'mime' => '...', 'size' => ..., 'width' => ...]
```

#### Webcam & URL import

You can extend the default upload dropzone with additional input methods. The following example adds both a camera capture tab and a remote URL import tab:

```php theme={null}
FlexImageUpload::make('vehicle_photo')
    ->label('Vehicle Photo')
    ->withRecommendedDefaults()
    ->imagesOnly()
    ->allowWebcamUpload() // Enables the native device camera tab
    ->allowUrlUpload()    // Enables the remote URL download tab
    ->optimizeImages()
    ->maxImageWidth(1920)
    ->maxImageHeight(1080)
    ->disk('public')
    ->directory('vehicle-photos');
```

### Configuration API

#### `withRecommendedDefaults()` / `applyRecommendedSecurityDefaults()`

Applies recommended security and UX defaults: `createFormStrategy()`, `deleteFileOnRemove()`, `deleteReplacedFiles()`, `maxSize(5120)` (5 MB), `downloadable()`, `openable()`, and `focusOutline()`.

```php theme={null}
FlexFileUpload::make('attachment')
    ->withRecommendedDefaults();
```

#### `documentsOnly()`

Sets the accepted file types to typical document formats (PDF, Word, Excel, PowerPoint, Text, etc.).

```php theme={null}
FlexFileUpload::make('resume')
    ->documentsOnly();
```

#### `imagesOnly()`

Sets the accepted file types to image formats (JPEG, PNG, GIF, WebP, SVG, etc.).

```php theme={null}
FlexImageUpload::make('photo')
    ->imagesOnly();
```

#### `spreadsheetsOnly()`

Sets the accepted file types to spreadsheets (CSV, XLS, XLSX).

```php theme={null}
FlexFileUpload::make('report')
    ->spreadsheetsOnly();
```

#### `allowedExtensions(array $extensions)`

Restricts uploads to a custom array of file extensions.

```php theme={null}
FlexFileUpload::make('scan')
    ->allowedExtensions(['pdf', 'jpg', 'png']);
```

#### `rejectExecutableFiles(bool|Closure $condition = true)`

Blocks dangerous executable extensions (such as `.php`, `.sh`, `.bat`, etc.) and raises a validation error.

```php theme={null}
FlexFileUpload::make('attachment')
    ->rejectExecutableFiles();
```

#### `scopedDirectory(string|Closure $prefix = 'uploads')`

Configures dynamic per-user scoped subdirectories: `{prefix}/{user_id}/...`.

```php theme={null}
FlexFileUpload::make('document')
    ->scopedDirectory('user-files');
```

#### `allowWebcamUpload(bool|Closure $condition = true)`

Adds a new "Camera" tab to the upload component, allowing users to directly capture photos using their device's native camera. It supports dynamic front/back camera toggling (`environment` vs `user` facing), torch/flash control (if supported by hardware), and gives the user a chance to review/retake the photo before injecting it into the queue.

*Note: Since it uses the `navigator.mediaDevices.getUserMedia` browser API, this feature requires a secure context (HTTPS) to function correctly. It perfectly integrates with `imagesOnly()` and Filament's `optimizeImages()` configurations.*

```php theme={null}
FlexImageUpload::make('inspection_photo')
    ->label('Vehicle Damage Photo')
    ->imagesOnly()
    ->multiple()
    ->maxFiles(3)
    ->allowWebcamUpload() // Enables the camera tab
    ->optimizeImages()
    ->maxImageWidth(1920)
    ->maxImageHeight(1080);
```

#### `allowUrlUpload(bool|Closure $condition = true)`

Adds a new "URL" tab to the upload component, allowing users to paste a direct link to a file. The file is fetched **server-side**, validated against SSRF rules (localhost, private IPs, and metadata hostnames are rejected), staged as a temporary preview, then injected into the FilePond queue as a native `File`. Nothing is written to the field disk until form save.

```php theme={null}
FlexFileUpload::make('attachment')
    ->label('Import Asset')
    ->withRecommendedDefaults()
    ->allowUrlUpload() // Enables the remote URL import tab
    ->disk('public')
    ->directory('imported-assets');
```

> **Security:** URL import is disabled unless you call `allowUrlUpload()`. Unsafe URLs are blocked before any server fetch runs.

#### `createFormStrategy(bool|Closure $condition = true)`

Prevents file path tampering by deferring disk storage until form submission.

```php theme={null}
FlexFileUpload::make('file')
    ->createFormStrategy();
```

#### `storeMetadataIn(string|Closure $statePath)`

Saves uploaded file metadata (original filename, MIME type, file size, image dimensions) to a separate database column or state path.

```php theme={null}
FlexFileUpload::make('document')
    ->storeMetadataIn('document_metadata');
```

#### `maxTotalSizeKb(int|Closure $kilobytes)`

Sets a maximum total file size limit in kilobytes across all uploaded files (useful for multiple file uploads).

```php theme={null}
FlexFileUpload::make('attachments')
    ->multiple()
    ->maxTotalSizeKb(10240); // 10 MB total limit
```

#### `remainingSlotsLabel(bool|Closure $condition = true)`

Displays a remaining slots label (e.g. "2 slots remaining") when `maxFiles` is set.

```php theme={null}
FlexFileUpload::make('gallery')
    ->multiple()
    ->maxFiles(5)
    ->remainingSlotsLabel();
```

#### `minImageDimensions(int $width, int $height)`

Validates that uploaded images meet minimum width and height constraints.

```php theme={null}
FlexImageUpload::make('banner')
    ->minImageDimensions(1200, 400);
```

#### `maxImageDimensions(int $width, int $height)`

Validates that uploaded images do not exceed maximum width and height constraints.

```php theme={null}
FlexImageUpload::make('thumbnail')
    ->maxImageDimensions(800, 600);
```

#### `deleteFileOnRemove(bool|Closure $condition = true)`

Deletes files from storage when they are removed from the form UI.

```php theme={null}
FlexFileUpload::make('document')
    ->deleteFileOnRemove();
```

#### `deleteReplacedFiles(bool|Closure $condition = true)`

Deletes old files from storage when they are replaced by new uploads.

```php theme={null}
FlexFileUpload::make('document')
    ->deleteReplacedFiles();
```

#### `pruneOrphanedOnSave(bool|Closure $condition = true)`

Removes old, unreferenced files from the upload directory when saving the model.

> **Warning**
> **Do not use this with a shared static `directory()`** (e.g., `->directory('gallery')`). This method deletes ALL files in the specified directory that do not belong to the current record. Using it on a shared directory will cause you to lose files from other records! You must use this method in combination with `->scopedDirectory()` or a closure that provides a unique directory per record.

```php theme={null}
FlexFileUpload::make('gallery')
    ->scopedDirectory('galleries')
    ->pruneOrphanedOnSave();
```

#### `uploadSummary(bool|Closure $condition = true)`

Displays a summary block below the file list containing count and total file size.

```php theme={null}
FlexFileUpload::make('attachments')
    ->multiple()
    ->uploadSummary();
```

#### `emptyStateHint(string|Closure $hint)`

Sets a custom hint text displayed inside the dropzone when it is empty.

```php theme={null}
FlexFileUpload::make('avatar')
    ->emptyStateHint('Drag your avatar here...');
```

#### `dropzoneLabel(string|Closure $label)`

Overrides the main dropzone label text.

```php theme={null}
FlexFileUpload::make('invoice')
    ->dropzoneLabel('Upload invoice (PDF)');
```

#### `requireReplaceConfirmation(bool|Closure $condition = true)`

Asks the user for confirmation before replacing an already uploaded file.

```php theme={null}
FlexFileUpload::make('document')
    ->requireReplaceConfirmation();
```

#### `compactList(bool|Closure $condition = true)`

Renders a denser, more compact layout for the uploaded files list.

```php theme={null}
FlexFileUpload::make('attachments')
    ->multiple()
    ->compactList();
```

#### `showFileIcon(bool|Closure $condition = true)`

Displays a descriptive file type icon in the uploaded files list.

```php theme={null}
FlexFileUpload::make('attachments')
    ->multiple()
    ->showFileIcon();
```

#### `variant(string|Closure $variant)`

Sets the visual design variant (`primary`, `secondary`, or `flat`).

```php theme={null}
FlexFileUpload::make('document')
    ->variant('flat');
```

#### `optimizeImages(bool|Closure $condition = true)`

Resizes and compresses images to optimize page weight (requires GD or Imagick).

```php theme={null}
FlexImageUpload::make('photo')
    ->optimizeImages();
```

#### `optimizeImagesToWebp(bool|Closure $condition = false)`

Converts optimized image files to the WebP format.

```php theme={null}
FlexImageUpload::make('photo')
    ->optimizeImagesToWebp();
```

#### `maxImageWidth(int|Closure $width)` / `maxImageHeight(int|Closure $height)`

Sets maximum image width and height boundaries for client-side resizing.

```php theme={null}
FlexImageUpload::make('photo')
    ->maxImageWidth(1920)
    ->maxImageHeight(1080);
```

#### `stripExif(bool|Closure $condition = true)`

Strips EXIF metadata from uploaded images on save.

```php theme={null}
FlexImageUpload::make('photo')
    ->stripExif();
```

### Inherited Filament `FileUpload` API

`disk()`, `directory()`, `visibility()`, `multiple()`, `maxFiles()`, `minFiles()`, `maxSize()`, `acceptedFileTypes()`, `imageEditor()`, `avatar()`, `downloadable()`, `openable()`, `previewable()`, `deletable()`, standard validation — all work unchanged.

### FlexField schema config

| Config key                             | Maps to                                |
| -------------------------------------- | -------------------------------------- |
| `disk`                                 | `disk()`                               |
| `directory`                            | `directory()`                          |
| `visibility`                           | `visibility()`                         |
| `multiple`                             | `multiple()`                           |
| `max_size_kb` / `max_size`             | `maxSize()`                            |
| `max_files` / `min_files`              | `maxFiles()` / `minFiles()`            |
| `max_total_size_kb`                    | `maxTotalSizeKb()`                     |
| `accepted_types`                       | `acceptedFileTypes()`                  |
| `documents_only`                       | `documentsOnly()`                      |
| `images_only`                          | `imagesOnly()`                         |
| `variant`                              | `variant()`                            |
| `size`                                 | `size()`                               |
| `store_metadata_in`                    | `storeMetadataIn()`                    |
| `scoped_directory`                     | `scopedDirectory()`                    |
| `optimize_images`                      | `optimizeImages()`                     |
| `max_image_width` / `max_image_height` | `maxImageWidth()` / `maxImageHeight()` |
| `allow_webcam_upload`                  | `allowWebcamUpload()`                  |
| `allow_url_upload`                     | `allowUrlUpload()`                     |

### Security

| Concern                  | Behaviour                                                                                                                                              |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Executable uploads**   | `rejectExecutableFiles()` blocks dangerous extensions (`.php`, `.sh`, …).                                                                              |
| **URL import SSRF**      | Server-side fetch rejects localhost, loopback, private/link-local IPs, `.local` / `.internal` hostnames, and cloud metadata endpoints before download. |
| **Webcam capture**       | Requires HTTPS (`getUserMedia` secure context). Not offered for `documentsOnly()` uploads.                                                             |
| **Deferred disk writes** | `createFormStrategy()` (included in `withRecommendedDefaults()`) prevents path tampering until form save.                                              |

### CSS classes

| Class                                              | Meaning      |
| -------------------------------------------------- | ------------ |
| `fff-flex-file-upload`                             | Root wrapper |
| `fff-flex-file-upload--{primary\|secondary\|flat}` | Variant      |
| `fff-flex-file-upload--{sm\|md\|lg}`               | Size         |

### Implementation notes

* Requires Livewire temporary uploads; configure `FILESYSTEM_DISK` and disk credentials.
* Webcam capture requires HTTPS. URL import rejects unsafe remote URLs before server fetch.
* Playground examples under **File upload** in Flex Fields Playground (File / Camera / URL tabs).
* For Spatie Media Library integration, see package `FlexSpatieMediaLibraryFileUpload` (if installed in app).

***

### Playground

Slug: **`file-upload`**

| Demo tab | Shows                                  |
| -------- | -------------------------------------- |
| File     | Documents, summaries, metadata sidecar |
| Camera   | Webcam capture (HTTPS)                 |
| URL      | Remote import with SSRF protection     |

`/admin/flex-fields-playground/file-upload` — see [Playground](/docs/index#playground).

***

### Related components

| Component                                                   | When to use instead                       |
| ----------------------------------------------------------- | ----------------------------------------- |
| [VideoField](/docs/videofield)                              | Video-specific upload and preview         |
| [AudioField](/docs/audiofield)                              | Audio recording and playback              |
| [SignatureField](/docs/signaturefield)                      | Drawn signature SVG, not file upload      |
| [FlexImageUpload](/docs/flexfileupload-and-fleximageupload) | Same component with `imagesOnly()` preset |

***
