
In Stimulus, you use HTML attributes to connect elements to “controllers,” which are chunks of JavaScript functionality. For example, if we wanted to provide a clipboard copy button, we could do something like this:
<div data-controller="clipboard">
<h1 data-clipboard-target="source">
Thimbleberry (Rubus parviflorus)
</h1>
<p>A delicate, native berry with large, soft leaves.</p>
<button data-action="click->clipboard#copy">
<span data-clipboard-target="feedback">Copy Name</span>
</button>
</div>
Notice the data-contoller attribute. That links the element to the clipboard controller. Stimulus uses a filename convention, and in this case, the file would be: clipboard_controller.js, with contents something like this:
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
// Connects to data-clipboard-target="source"
// and data-clipboard-target="feedback"
static targets = [ "source", "feedback" ]
// Runs when data-action="click->clipboard#copy" is triggered
copy() {
// 1. Get text from the "source" target
const textToCopy = this.sourceTarget.textContent
// 2. Use the browser's clipboard API
navigator.clipboard.writeText(textToCopy)
// 3. Update the "feedback" target to tell the user
this.feedbackTarget.textContent = "Copied!"
// 4. (Optional) Reset the button after 2 seconds
setTimeout(() => {
this.feedbackTarget.textContent = "Copy Name"
}, 2000)
}
}
The static target member provides those elements to the controller to work with, based on the data-clipboard-target attribute in the markup. The controller then uses simple JavaScript to perform the clipboard copy and a timed message to the UI.

