Rails 6 + Bootstrap 5

sebdur
4 min readDec 16, 2020

Bootstrap v5.0.0-beta1 was released 10 days ago, and some new awesome features are included. As we’re used to, the docs are very clear.

You can check the new stuff https://getbootstrap.com/

In my opinion, the big thing about v5 is the removal of jQuery as a dependency.

Since 2017, Rails 5.1 was already removed the dependency of jQuery.

So, that’s the way.

Specially for me, it meant an extreme change in my JS code, because I get used to handling the DOM with jQuery.

jQuery is deprecated for many reasons, but it’s not the purpose of my post. You can read this reference in case you’re interested https://modernweb.com/replacing-jquery-with-vanilla-javascript/

In my case, after reading and learning about other JS libraries or frameworks, such as TS, Vue.js, Angular, React…I decided to migrate my jQuery code to Vanilla JS (or Plain JS) for DOM manipulation, because the syntax looks a lot like jQuery (but, in general, it’s very different), and I was excited by the idea of working with the language that browsers read directly, without doing it through a JS library.

Let’s go.

Versions

Create new project

$ rails new railsbs -d postgresql
$ cd railsbs
$ rails g controller Home index
$ rails db:create db:migrate

In config/routes.rb replace get ‘home/index’ with root ‘home#index’

Start server:

$ rails s
Everything’s OK.
Everything’s OK.

Next step, install Bootstrap via yarn (and popper.js as dependency)

Run this command:

$ yarn add bootstrap @popperjs/core

When the installation is finished, you need to import bootstrap.scss (located in node_modules folder) through app/javascript/packs/application.js

First, we must use the stylesheet_pack_tag in the application layout app/views/layouts/application.html.erb and don’t forget to include the responsive <meta>

Your <head> tag it should be like this:

<head>
<title>Railsbs</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>

To create a new folder app/javascript/stylesheets and add file app/javascript/stylesheets/application.scss run this:

$ mkdir -p app/javascript/stylesheets
$ touch app/javascript/stylesheets/application.scss

Open the .scss file, and paste this line over the top of the file (line 1):

@import "bootstrap";

By doing this, you’ll put your stylesheets in app/javascript/stylesheets folder, so that they can be handled through Webpack.

Now, we need to go to app/javascript/packs/application.js

We will define the ‘bootstrap’ in global scope, and declare the require to our new application.scss file.

Your application.js it should be like this:

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("stylesheets/application.scss")
window.bootstrap = require("bootstrap");

To prove it, I will add some tooltips.

In the same application.js file, you can enable tooltips everywhere (don’t forget to use document.addEventListener('turbolinks:load', () => {}); , to avoid conflicts with turbolinks).

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("stylesheets/application.scss")
window.bootstrap = require("bootstrap");document.addEventListener('turbolinks:load', ()=> {
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
});

In app/views/home/index.html.erb you can copy/paste some tooltips from https://getbootstrap.com/docs/5.0/components/tooltips/ and then start the server.

<h1>Home#index</h1>
<p>Find me in app/views/home/index.html.erb</p>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top">
Tooltip on top
</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" title="Tooltip on right">
Tooltip on right
</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tooltip on bottom">
Tooltip on bottom
</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" title="Tooltip on left">
Tooltip on left
</button>
Voila!

One more thing:

In bootstrap documentation, specifically in downloads/npm, they suggest you to add const bootstrap = require('bootstrap') or import bootstrap from 'bootstrap' in your app/javascript/packs/application.js instead of my solution line window.bootstrap = require("bootstrap")

I did it on this way, because by doing this, you can declare the variable in global scope, that’s allow us to use it in the entire project. For example, if you use UJS (remote: true), when you do the respond_to via format.js and need to create a new bootstrap component, like a modal, you couldn’t do it with const bootstrap = require('bootstrap') (console would print something like: bootstrap variable doesn’t exist).

That’s all, thanks for reading.

Enjoy it!

--

--