DEV Community

Cover image for Drag & Drop Images with Preview using Stimulus Outlets
Rails Designer
Rails Designer

Posted on β€’ Originally published at railsdesigner.com

4

Drag & Drop Images with Preview using Stimulus Outlets

This articles was originally published on Rails Designer


In a previous article I explored a way to preview images before upload with Stimulus.

I know want to extend its functionality by adding a drag & drop. Along the way I am also using Stimulus outlets to tie the two functionalities together. Showcasing more advanced use of small Stimulus controllers.

I assume you walked through all the steps of the previous mentioned article.

Let's start with the HTML. It's using the other HTML with just a few attributes added.

<div data-controller="image-preview dropzone" data-action="dragover->dropzone#dragOver dragleave->dropzone#dragLeave drop->dropzone#drop">
  <img data-image-preview-target="canvas" hidden class="object-cover size-48">

  <input type="file" accept="image/*" data-image-preview-target="source" data-dropzone-target="input" data-action="image-preview#show" hidden>
</div>
Enter fullscreen mode Exit fullscreen mode

Let's create the dropzone_controller.js.

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["input"];

  dragOver(event) {
    event.preventDefault();
  }

  dragLeave(event) {
    event.preventDefault();
  }

  drop(event) {
    event.preventDefault();

    this.#updateInputField(event.dataTransfer.files[0]);
  }
}
Enter fullscreen mode Exit fullscreen mode

All these methods do is preventing the default event when these actions are invoked. The drop() function also calls the private function this.#updateInputField(). Let's add it.

export default class extends Controller {
  // …

  // private
  #updateInputField(file) {
    const dataTransfer = new DataTransfer();

    dataTransfer.items.add(file);

    this.inputTarget.files = dataTransfer.files;
  }
  // …
}
Enter fullscreen mode Exit fullscreen mode

This will inject the dropped image into the inputTarget field. And just like that you can drag and drop images onto the element. 🀯

Preview images with outlets

An important part is missing though… the image isn't show which looks like a bug. Luckily with the image_preview_controller.js already done. This is a simple exercise.

First tweak the HTML by adding the following attributes:

<div data-controller="image-preview dropzone" data-dropzone-image-preview-outlet="#image-preview" data-action="dragover->dropzone#dragOver dragleave->dropzone#dragLeave drop->dropzone#drop" id="image-preview>
  <img data-image-preview-target="canvas" hidden class="object-cover size-48">

  <input type="file" accept="image/*" data-image-preview-target="source" data-dropzone-target="input" data-action="image-preview#show" hidden>
</div>
Enter fullscreen mode Exit fullscreen mode

Added:

  • data-dropzone-image-preview-outlet="#image-preview";
  • id="image-preview".

Now two lines are needed in the dropzone_controller.js.

export default class extends Controller {
  static outlets = ["image-preview"];
  // …

  drop(event) {
    // …

    this.imagePreviewOutlet.show();

    // …
  }

  // …
}
Enter fullscreen mode Exit fullscreen mode

Now when you drop an image it fires the show() function on the image_preview_controller.js. πŸ₯³

I like to use small Stimulus controllers like these that work great together.


Rails Designer has this Stimulus controller packaged with a few extras added. Get your copy today.

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs