DEV Community

Cover image for Preview an Image Before Upload with Hotwire/Stimulus
Rails Designer
Rails Designer

Posted on • Originally published at railsdesigner.com

Preview an Image Before Upload with Hotwire/Stimulus

This article was originally published on Rails Designer


Giving your users the option to preview an image, like a profile picture, can be a great UX improvement. Next to that it give them a preview on how the image will look. Specifically useful for the ever fully rounded profile picture where a picture can just look off a bit.

It works like this:

  • give an user the option to upload a profile picture;
  • after selecting an image (via a input type=file);
  • a preview of the image is shown.

Modern JavaScript comes with the FileReader interface that makes this easy. Let's wrap it into a small Stimulus controller, ready to be copied & pasted in your Rails app.

Let's look at the required HTML needed first:


<div data-controller="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-action="image-preview#show">
</div>

Enter fullscreen mode Exit fullscreen mode

Nothing special here. Instantiate the image-preview controller and set the targets: canvas (where the image will be previewed; hidden by default) and a source target. Notice that this input-element also uses a accept attribute that only allows image-types.

And then the full Stimulus controller.

// app/javascripts/controllers/image_preview_controller.js
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  static targets = ["canvas", "source"];

  show() {
    const reader = new FileReader();

    reader.onload = function () {
      this.canvasTarget.removeAttribute("hidden");

      this.canvasTarget.src = reader.result;
    }.bind(this)

    reader.readAsDataURL(this.sourceTarget.files[0]);
  }
}
Enter fullscreen mode Exit fullscreen mode

The show() function sets up a FileReader. When the image is loaded, the onload function is triggered, which updates the canvas target by setting its src attribute to the loaded file's result and removing the hidden attribute. Then the file is read, converting it to a Data URL (which can be used directly in img-tags or other elements that accept source attributes).

And that's it really! 🤯 From here you can make some UI and UX improvements:

  • beautify the input-element with CSS;
  • show a default/fallback profile picture;
  • validate there's only one image loaded;
  • add an option to remove the profile picture (really straight-forward to do with TurboStream responses!).

Or you can try the Image Preview Component from Rails Designer (feel free to steal some CSS ideas 😅).

Top comments (1)

Collapse
 
railsdesigner profile image
Rails Designer

You are of course not limited to profile picture. Previewing a profile hero image can also be a great use-case. Got other ideas? I might steal it to add it to Rails Designer! 😄