Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ux Dropzone Laravel Package

symfony/ux-dropzone

Symfony UX Dropzone adds lightweight drag-and-drop file uploads to Symfony Forms, letting visitors drop files into a container instead of browsing their computer. Part of the Symfony UX initiative.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Confirm you're in a Symfony app (or a Symfony-based package), not a Laravel one. symfony/ux-dropzone is a Symfony UX bundle — it ships an extra Form type plus a Stimulus controller and a Twig form theme. There is no Laravel service provider, no Blade integration, and no laravel/symfony-bridge. Inside a Laravel application the package will install but do nothing; Laravel projects should use dropzone (npm) directly or a Filament/Livewire upload component instead.

  2. Install the bundle (Flex handles the wiring):

    composer require symfony/ux-dropzone
    

    The Flex recipe registers the bundle, adds the dropzone Stimulus controller to assets/controllers.json, and registers the form theme. Verify with php bin/console debug:stimulus (controller present) and php bin/console debug:asset-map (JS in the map).

  3. Install the frontend package:

    php bin/console importmap:require @symfony/ux-dropzone   # AssetMapper
    # or
    npm install -D @symfony/ux-dropzone                       # Webpack Encore / Vite
    
  4. Use the type in a form — it extends FileType, so all standard file options still apply:

    use Symfony\UX\Dropzone\Form\DropzoneType;
    
    $builder->add('avatar', DropzoneType::class, [
        'label' => 'Drag your photo here',
        'constraints' => [
            new Assert\File(maxSize: '2M', mimeTypes: ['image/jpeg', 'image/png']),
        ],
    ]);
    
  5. Render it and handle the upload — the form theme produces the dropzone markup automatically, so form_row() is enough:

    {{ form_start(form) }}
        {{ form_row(form.avatar) }}
        <button>Save</button>
    {{ form_end(form) }}
    
    $form->handleRequest($request);
    if ($form->isSubmitted() && $form->isValid()) {
        /** @var UploadedFile $file */
        $file = $form->get('avatar')->getData();
        $file->move($this->getParameter('avatars_dir'), $file->getClientOriginalName());
    }
    

First Use Case

Replace a plain <input type="file"> on a profile/settings page with a drag-and-drop zone, while keeping Symfony's validation pipeline as the source of truth for allowed MIME types and size. The browser is a convenience layer; the File constraint still rejects bad uploads server-side.


Implementation Patterns

Basic single upload + constraint-as-config

Keep validation out of the JS: pass maxSize/mimeTypes only through the File constraint so client hints and server rules can't drift apart. If you want the zone to show a friendly limit, mirror the same value in attr:

$builder->add('cv', DropzoneType::class, [
    'constraints' => [new Assert\File(maxSize: '5M', mimeTypes: ['application/pdf'])],
    'attr' => ['data-dropzone-max-size' => '5M'],
]);

Multiple files with an entity collection

DropzoneType is a FileType, so multiple => true produces an array of UploadedFile. The common pattern is a mapped CollectionType of file entities, or an unmapped multiple file field processed in the controller:

$builder->add('attachments', DropzoneType::class, [
    'multiple' => true,
    'mapped' => false,
    'constraints' => [new Assert\All([new Assert\File(maxSize: '10M')])],
]);

// controller
foreach ($form->get('attachments')->getData() as $file) {
    $entity->addAttachment(Attachment::fromUpload($file));
}

Async/queued uploads

For large files or immediate previews, point the dropzone at a dedicated upload controller (POST /uploads, returns JSON {id, url}), store the file, and keep only the returned identifier on the form (a hidden field or EntityType). This decouples the browser's upload from form submit and gives you a place to enforce auth, virus scanning, and quota limits.

Customising behaviour

Extend the shipped Stimulus controller rather than re-initialising Dropzone on the same element:

// assets/controllers/my_dropzone_controller.js
import DropzoneController from '@symfony/ux-dropzone/controller';
import { Controller } from '@hotwired/stimulus';

export default class extends DropzoneController {
    connect() {
        super.connect();
        this.dropzone.options.maxFiles = 5;
        this.dropzone.options.acceptedFiles = 'image/*';
    }
}

Override the template with data-controller="my-dropzone" in attr, and keep the bundle's controller registered so its previewTemplate/i18n defaults stay intact.

Styling and templates

The bundle ships a form theme; if you have a custom form theme, ensure it uses the dropzone theme (or that form_themes in twig.yaml lists it) or you'll silently get a bare file input. Override the widget by defining _dropzone_widget.html.twig in your own theme block, not by copying the vendor file.

Testing

Uploads are testable with KernelBrowser::submit()'s file arguments, or by constructing a UploadedFile from a fixture path (new UploadedFile($path, 'cv.pdf', 'application/pdf', null, true)) and submitting the form directly via $form->submit([...]). Dropzone's JS behaviour isn't exercised by Symfony's functional tests — the non-JS fallback path is what you're actually asserting.


Gotchas and Tips

  • v3.6.0 adds a Composer conflict with symfony/asset-mapper 8.2 and later. If your app uses AssetMapper, a future composer update that resolves asset-mapper to 8.2+ will now fail with a dependency conflict instead of failing at runtime. Pin symfony/asset-mapper below 8.2 (or upgrade symfony/ux-dropzone when the constraint is lifted). This is the only item in this release with day-to-day impact; the rest is tooling dependency bumps and a docs-only change replacing a hardcoded version with an X.Y.Z placeholder in the assets README.
  • No breaking changes, no deprecations in 3.6.0. No code changes are required to upgrade from 3.5.x.
  • Bundle present ≠ widget rendered. The most common "it does nothing" report is a missing form theme registration; check twig.form_themes and that the recipe's form_themes entry wasn't removed by a manual twig.yaml.
  • Stimulus controller not firing. With AssetMapper, confirm @symfony/ux-dropzone is in importmap.php; with Encore, confirm the package is imported in app.js and that controllers.json has the dropzone entry with "enabled": true. php bin/console debug:stimulus is faster than grepping build output.
  • PHP limits still win. Dropzone's client-side maxFiles/size hints don't change upload_max_filesize, post_max_size, or max_file_uploads. A large multi-file submit silently truncates to max_file_uploads — validate the count with Count on the field if that matters.
  • Chunked uploads are client-only. Dropzone's chunking reassembles server-side from separate PHP requests; PHP still enforces post_max_size per chunk, and you must handle reassembly yourself. Don't enable chunking without an async upload endpoint.
  • No JS fallback is automatic but unstyled. The markup degrades to a normal file input, which conveniently lets you test the real server-side path by disabling JS.
  • CSRF and auth on async endpoints. A separately-routed upload controller bypasses form CSRF tokens by default — protect it with a firewall rule, a signed token, or an authenticated session check, and validate file contents server-side regardless of the accept attribute.
  • Extension point for behaviour is the Stimulus controller, not the Form type. DropzoneType only exposes inherited FileType options; anything dropzone-specific (previews, autoProcessQueue, dict defaults) lives in JS via inherited controller methods or data-* attributes.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource