A very simple tutorial about Rails 8 and Bootstrap 5, since starting with Boostrap is given by the framework.

· Ruby  · 5 min read

Rails 8 Bootstrap 5 tutorial

A very simple tutorial about Rails 8 and Bootstrap 5, since starting with Boostrap is given by the framework.

Motivation

Bootstrap used to be the de-facto CSS Frameworks for a long time. Now it’s more Tailwind, but Rails 8 still gives the option to use Bootstrap by default.

1. Prerequisites

I tested on Linux with the tools below :

$> ruby -v
ruby 3.3.0
$> bundle -v
Bundler version 2.5.5
$> npm -v
10.2.4
$> yarn -v
1.22.22

Any upper versions should work.

2. Create an isolated, new Rails 8 app

mkdir myapp && cd myapp
echo "source 'https://rubygems.org'" > Gemfile
echo "gem 'rails', '8.0.0'" >> Gemfile
bundle install
bundle exec rails new . --force --css=bootstrap -j=esbuild

Continue inside bash :

bin/rails db:create
bin/rails db:migrate

3. Is Bootstrap v5 already installed ? a check

In this paragraph, we will not write any code, instead, we will read what is already installed for us.

Some good news : maybe you noticed the --css=bootstrap option above. This means the last Bootstrap version is already installed.

Let’s check where this happens :

package.json

// inside package.json
{
  "name": "app",
  "private": "true",
  // ... other props, the
  "dependencies": {
    "@hotwired/stimulus": "^3.2.2",
    "@hotwired/turbo-rails": "^8.0.12",
    "@popperjs/core": "^2.11.8",
    "autoprefixer": "^10.4.20",
    "bootstrap": "^5.3.3",
    "bootstrap-icons": "^1.11.3",
    "nodemon": "^3.1.7",
    "postcss": "^8.4.49",
    "postcss-cli": "^11.0.0",
    "sass": "^1.81.0"
  },
}

Ok ! Bootstrap 5 and its dependencies is properly installed inside package.json

// inside app/assets/stylesheets/application.bootstrap.scss
@import 'bootstrap/scss/bootstrap';
@import 'bootstrap-icons/font/bootstrap-icons';

Great ! Standard import of bootstrap scss source, this will allow us fine tuning later.

// inside app/javascript/application.js
// Entry point for the build script in your package.json
import '@hotwired/turbo-rails';
import './controllers';
import * as bootstrap from 'bootstrap';

Ok ! JavaScript for Bootstrap is now loaded - even if no initialisation happens so far.

Open app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= content_for(:title) || "Myapp" %></title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= yield :head %>

    <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
    <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>

    <link rel="icon" href="/icon.png" type="image/png">
    <link rel="icon" href="/icon.svg" type="image/svg+xml">
    <link rel="apple-touch-icon" href="/icon.png">

    <%# Includes all stylesheet files in app/assets/stylesheets %>
    <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
    <%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

The interesting lines are javascript_include_tagand stylesheet_link_tag. They allow us to profit from initial SCSS and JS files in each template that inherits from the default layout.

Create bare minimal Bootstrap 5 HTML

Create a controller :

# inside app/controllers/home_controller.rb
class HomeController < ApplicationController
end

Configure a default route :

# inside config/routes.rb
Rails.application.routes.draw do
  get "home/index"
  root to: "home#index"
end

Now create a view tailored for Bootstrap 5 : just copy/paste the code below into app/views/home/index.html.erb

<!-- inside app/views/home/index.html.erb -->
<h1>Welcome, this is the home page</h1>

<button
  type="button"
  class="btn btn-lg btn-danger"
  data-bs-toggle="popover"
  title="Popover title"
  data-bs-content="Amazing content, right ?"
>
  Click to toggle popover
</button>

This HTML should show a popover when clicking the red button, only if

  • Bootstrap CSS is properly configured,
  • Bootstrap JS is loaded and initialized.

Great ! This bare minimalistic example will ensure everything works properly.

Bootstrap 5, Rails 8, locally : let’s start !

$/myapp> ./bin/dev

17:24:24 web.1 | started with pid 26889
17:24:24 js.1 | started with pid 26890
17:24:24 css.1 | started with pid 26891
17:24:24 css.1 | yarn run v1.22.10
17:24:24 js.1 | yarn run v1.22.10
17:24:24 css.1 | $ sass ./app/assets/stylesheets/application.bootstrap.scss ./app/assets/builds/application.css --no-source-map --load-path=node_modules --watch
17:24:24 js.1 | $ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --watch
17:24:25 js.1 | [watch] build finished, watching for changes...
17:24:25 css.1 | Sass is watching for changes. Press Ctrl-C to stop.
17:24:25 css.1 |
17:24:26 web.1 | => Booting Puma
17:24:26 web.1 | => Rails 7.0.0 application starting in development
17:24:26 web.1 | => Run `bin/rails server --help` for more startup options
17:24:26 web.1 | Puma starting in single mode...
17:24:26 web.1 | * Puma version: 5.5.2 (ruby 3.0.0-p0) ("Zawgyi")
17:24:26 web.1 | * Min threads: 5
17:24:26 web.1 | * Max threads: 5
17:24:26 web.1 | * Environment: development
17:24:26 web.1 | * PID: 26889
17:24:26 web.1 | * Listening on http://127.0.0.1:3000
17:24:26 web.1 | * Listening on http://[::1]:3000
17:24:26 web.1 | Use Ctrl-C to stop

Great ! the console indicates that we should go to localhost:3000 to see what is happening. Let’s go :

localhost
localhost

Try to click the button. Nothing happens.

Adding custom Bootstrap-based JavaScript into Rails

Let’s follow the Bootstrap docs about popovers here :

And inject it into Rails

// Inside app/javascript/application.js  
import "@hotwired/turbo-rails"  
import "./controllers"  
import * as bootstrap from "bootstrap"  
  
let popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))  
let popoverList = popoverTriggerList.map(function (popoverTriggerEl) {  
  return new bootstrap.Popover(popoverTriggerEl)  
})  

Now reload your browser, and click the big red button

localhost
localhost

Great ! it works

Add custom SCSS

// inside app/assets/stylesheets/application.bootstrap.scss  
$h1-font-size: 1rem; // this line was added  
@import 'bootstrap/scss/bootstrap';  

Reload your browser

A smaller h1 title
A smaller h1 title

Summary

I tried to write the most possible Rails 8 and Bootstrap 5 tutorial, hope it helped.

Enjoy!

Share:
Back to Blog

Related Posts

View All Posts »
The simplest turbo-frame example

The simplest turbo-frame example

Turbo frame is a powerful feature of Hotwire, here is a quick memo about how to follow conventions in the simplest case. Convention over configuration is powerful, but sometimes it is also a problem when you are not sure anymore about conventions ;) so I plan to release more "simplest *** Hotwire feature".

My honest opinion about Hatchbox

My honest opinion about Hatchbox

Hatchbox.io is a deployment platform for Ruby-on-Rails users. I used it recently, so for people ashamed of trying, here is my review.