Listening to Bootstrap Events in Stimulus Controllers

Posted on

I love Bootstrap 4 & Stimulus, both are fantastic libraries that allow me to develop at a good pace without making a mess. However they require a bit of setup to help them play nicely together.

If you want to skip ahead and see the working final solution, I’ve posted the code to GitHub, which you can deploy to Heroku to see it working.

The Approach

Bootstrap events (like & are triggered via the jQuery trigger() method, which unfortunately doesn’t create an event that we can listen to via addEventListener, which means I can’t bind the events to data-action like stimulus encourages.

Instead, I’m going to explicitly bind the events in the Stimulus controller using the jQuery on() method.

The Stimulus Controller

// app/javascript/controllers/open_counter_controller.js
// Visit The Stimulus Handbook for more details 

import { Controller } from "stimulus"

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

  connect() {
    let openCounterController = this;
    this.openCount = 0;

    // The listener for the Bootstrap event via jQuery
    $(this.element).on('', (event) => {

  incrementCount() {
    this.openCountOutputTarget.textContent = this.openCount;


I took this from the Bootstrap Modal Docs, and then sprinkled in the data-controller="open-counter" & data-target="open-counter.openCountOutput" attributes.

<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  Launch demo modal

<!-- Modal -->
  class="modal fade"
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
      <div class="modal-body">
        <p>You've opened this modal <span data-target="open-counter.openCountOutput">0</span> times</p>

Making jQuery available everywhere via Webpacker

One of the big “gotchas” of the modern approach to JavaScript is everything should be broken up into modules, where each module specifies what libraries it requires. This helps Webpacker optimise your code when you compile it for production, but can be a little annoying when working with old jQuery plugins.

But don’t worry, if you modify your config/webpack/environment.js file you can use jQuery like before:

// config/webpack/environment.js
const { environment } = require('@rails/webpacker')

// Add the following section to make jQuery play nicely with Webpacker.
// From:
const webpack = require("webpack");
  new webpack.ProvidePlugin({
    $: "jquery",
    jQuery: "jquery"

module.exports = environment