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>
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]);
}
}
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)
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! 😄