Copy text to a user’s clipboard using Stimulus.js
Stimulus.js is a lightweight approach for adding some interactivity to server-rendered applications using templating languages like ERB in Rails or EEX in Phoenix.
Let's try using it to build a button for storing information into the user's system clipboard.
A quick intro to Stimulus.js
A whirlwind tour of Stimulus.js is in order. Essentially, Stimulus works by wiring up DOM elements to JavaScript classes that it calls controllers
using data
attributes.
data-controller
is used to wire up a Stimulus controllerdata-[controller-name-here]-target
is used to wire up elements of importance that are inside thedata-controller
elementdata-action
is used to wire up events to methods in our Stimulus controllers
Adding our markup
Let's add the HTML (in our case we'll be writing ERB) and pretend that were adding a button to copy the current branch name on GitHub.
<div data-controller="clipboard" class="mr-2">
<%= hidden_field_tag(
:branch,
@current_branch.name,
data: { clipboardTarget: "source" },
readonly: true
)
%>
<button data-action="clipboard#copy">
Copy branch
</button>
</div>
In this case, we're wiring up our div
to our Stimulus controller defined in clipboard_controller.js
, attaching a hidden input as our source
, and wiring up our button to the copy()
method in our controller.
Adding our Stimulus controller
In a file named clipboard_controller.js
add the following:
import { Controller } from "stimulus";
export default class extends Controller {
// define our targets in our controller
static get targets() {
return ["source"];
}
// define our copy action
copy() {
alert("hello, this is the clipboard copy action!")
}
}
With this is in place, our clipboard controller should be successfully wired up. Now we just need to make it useful!
Leveraging the web's Clipboard API
I was able to find the Web API for writing to a user's clipboard on MDN.
import { Controller } from "stimulus";
export default class extends Controller {
// define our targets in our controller
static get targets() {
return ["source"];
}
// define our copy action
copy() {
navigator.clipboard.writeText(this.sourceTarget.value);
}
}
Since we added the data-clipboard-target="source"
attribute to our hidden input, it is now available to us in our Stimlus controller using this.sourceTarget
. In the example above, we're grabbing the value
of our hidden input, which is currently set to @current_branch.name
in our template.
Wrap-up
That should do it! There's room for improvement for our little feature here. We're not providing any user feedback that copying to the clipboard was successful, and maybe the clipboard-copy heroicon SVG would look nice here as well. But I'll leave that to you :)
Hope you enjoyed this whirlwind introduction for using Stimulus.js to make the lives of your users just a bit easier. Cheers!