August 13th, 2021

How to Install Bootstrap 5 on Ruby on Rails 6 with Webpack


In this tutorial I’ll be explaining how to install Bootstrap 5 with Ruby on Rails 6 using Webpack. There are some great tutorials out there for Bootstrap 4, but Bootstrap 5 requires some subtle but important changes to get working properly. Let’s begin.

Covered in this guide:

  • Installing Bootstrap 5 via a package manager
  • Configuring Webpacker to utilize Bootstrap and it’s dependencies
  • Configuring Bootstrap to enable Javascript features such as Popper and Tooltips

What we’ll be using:

  • Bootstrap 5.1
    • Any 5.x version should be fine
  • Rails 6.0.4
    • Newer versions of Rails should work as well.
  • Webpack
    • I’m using the default version bundled with Rails (4.46.0)

Step 1: Install Packages

Using your favorite package manager, install the following packages:

Terminal
yarn add bootstrap jquery @popperjs/core

# Or

npm install bootstrap jquery @popperjs/core

Not popper.js?

The Popper team has released Popper 2, and with it a new package name. Many old tutorials reference popper.js, which won't work with Bootstrap 5. The new one should be @popperjs/core to work properly with Bootstrap 5.

Step 2: Configure Webpacker

Navigate to the following file and update it with the following code:

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

// Add the following lines
const webpack = require("webpack")

environment.plugins.append("Provide", new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']  // Not a typo, we're still using popper.js here
}))
// End new addition

module.exports = environment

Why is this important?

The code above allows (or better yet, tells) Webpack to automatically load those modules instead of having to import or require them everywhere. So when we reference them in our source Javascript code, they'll be available. This is important for Bootstrap because it is expecting those modules to be accessible.

You can read more about the Webpack ProvidePlugin here.

Next, we need to setup Webpack to know where our Bootstrap CSS is located. Create a new folder called stylesheets in /app/javascript. Then create a file called application.scss within that new folder. Update it with the following line:

/app/javascript/stylesheets/application.scss
@import "~bootstrap/scss/bootstrap";

Finally, we need to update our application.js file to load Bootstrap:

/app/javascript/packs/application.js
/* You may have a few 'require' lines above this already */

require("@popperjs/core")

import "bootstrap"

// Import the specific modules you may need (Modal, Alert, etc)
import { Tooltip, Popover } from "bootstrap"

// The stylesheet location we created earlier
require("../stylesheets/application.scss")

// If you're using Turbolinks. Otherwise simply use: jQuery(function () {
document.addEventListener("turbolinks:load", () => {
    // Both of these are from the Bootstrap 5 docs
    var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
    var tooltipList = tooltipTriggerList.map(function(tooltipTriggerEl) {
        return new Tooltip(tooltipTriggerEl)
    })

    var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))
    var popoverList = popoverTriggerList.map(function(popoverTriggerEl) {
        return new Popover(popoverTriggerEl)
    })
})

Step 3: Test Everything is Working

You should be set! Let’s test to ensure everything is loading and working right.

Part 1: Create a View

If you don’t have any views (aka pages) yet, quickly create one using the following commands/code. Otherwise, skip to Part 2.

Terminal
rails g controller home index

And update your routes.rb file:

Terminal
Rails.application.routes.draw do
  root to: 'home#index'
end

Then start your server:

Terminal
rails s

Part 2: HTML

In your application.html.erb, add the following Bootstrap 5 code snippets to test:

/app/views/layouts/application.html.erb
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="#">Navbar</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                <li class="nav-item">
                    <a class="nav-link active" aria-current="page" href="#">Home</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Link</a>
                </li>
                <li class="nav-item dropdown">
                    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                        Dropdown
                    </a>
                    <ul class="dropdown-menu" aria-labelledby="navbarDropdown">
                        <li><a class="dropdown-item" href="#">Action</a></li>
                        <li><a class="dropdown-item" href="#">Another action</a></li>
                        <li>
                            <hr class="dropdown-divider">
                        </li>
                        <li><a class="dropdown-item" href="#">Something else here</a></li>
                    </ul>
                </li>
                <li class="nav-item">
                    <a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
                </li>
            </ul>
            <form class="d-flex">
                <input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-success" type="submit">Search</button>
            </form>
        </div>
    </div>
</nav>

<!-- Tooltips -->
<button type="button" class="btn btn-primary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top">
    Tooltip on top
</button>

<!-- Popover -->
<button type="button" class="btn btn-secondary" data-bs-container="body" data-bs-toggle="popover" data-bs-placement="top" data-bs-content="Top popover">
    Popover on top
</button>

Then navigate to localhost:3000, and you should see everything is working properly.

Happy development! 🎉