In this post we will take a freshly-created Rails 6 app and set up React with Bootstrap 4 such that both the Rails and React-based views can use Bootstrap components.
Setting up Bootstrap 4
Install the necessary dependencies
yarn add bootstrap jquery popper.js
Update config/webpack/environment.js
Here we add configuration for ProvidePlugin
so that jQuery and popper.js are
available in all views:
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
$: 'jquery',
JQuery: 'jquery',
Popper: ['popper.js', 'default'], // for Bootstrap 4
})
)
module.exports = environment
Add import for bootstrap to app/javascript/stylesheets/application.scss
First, rename the stylesheet if you haven’t done so already:
mv app/javascript/stylesheets/application.css app/javascript/stylesheets/application.scss
Then add the import statement:
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
*/
@import "bootstrap/scss/bootstrap";
Add your first page
Assuming you are still seeing the Rails welcome view, we need to set up the first view, e.g.:
config/routes.rb
:
Rails.application.routes.draw do
root 'pages#main'
end
app/controller/pages_controller.rb
:
class PagesController < ApplicationController
def main
end
end
Then add an empty template file:
mkdir app/views/pages
touch app/views/pages/main.html.erb
On loading this view if you put some placeholder content into the
main.html.erb
template then you should see it rendered with Bootstrap’s
default styling.
Some example placeholder content to exercise Bootstrap:
<div class="alert alert-primary" role="alert">
A simple primary alert to test Bootstrap with.
</div>
Update the layout
Finally let’s set up the layout to include the necessary Bootstrap meta tags, and a container for the view contents:
In app/views/layouts/application.html.erb
:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Hello, world!</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all' %>
<%= javascript_pack_tag 'application' %>
</head>
<body>
<div class="container">
<%= yield %>
</div>
</body>
</html>
React Setup
Run the built-in installer:
bin/rails webpacker:install:react
This will install the necessary dependencies and update your babel and webpacker configurations to transpile JSX for you, amongst other things.
It creates an example pack (entry point) using React which you can use to test the integration.
The example pack lives at app/javascript/packs/hello_react.jsx
, so in your
root view (in our case app/views/pages/main.html.erb
) you can add the
following to load it:
<%= javascript_pack_tag 'hello_react' %>
For reference the code for hello_react.jsx
is:
// Run this example by adding <%= javascript_pack_tag 'hello_react' %> to the head of your layout file,
// like app/views/layouts/application.html.erb. All it does is render <div>Hello React</div> at the bottom
// of the page.
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const Hello = props => (
<div>Hello {props.name}!</div>
)
Hello.defaultProps = {
name: 'David'
}
Hello.propTypes = {
name: PropTypes.string
}
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<Hello name="React" />,
document.body.appendChild(document.createElement('div')),
)
})
What it’s doing is setting up a basic React component, and then rendering it into a div that it’s appending to the end of the page content. This way there’s no need to have a particular element available in the page to render into.
At this point you would want to set up your own entry point / pack for your application or view.
As we are going to load this pack via the pages#main
for this simple app, we
will rename the entrypoint appropriately:
mv app/javascript/packs/hello_react.jsx app/javascript/packs/main.jsx
Loading the Rails app now gives us ‘Hello React!’ rendered using Bootstrap’s basic styling.
Settting up react-bootstrap
Install react-bootstrap
:
yarn add react-bootstrap
We can now test the integration by including a react-bootstrap component in our view, in this case a button:
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
import Button from 'react-bootstrap/Button';
const Hello = props => (
<Button>Hello {props.name}!</Button>
)
Hello.defaultProps = {
name: 'David'
}
Hello.propTypes = {
name: PropTypes.string
}
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<Hello name="React" />,
document.getElementById('application'),
)
})
On reloading the page you should see a Bootstrap-styled button.
Wrapping Up
At this point you should now have a working Rails 6 app with:
- Bootstrap 4 styles loaded
- A JS entry point which loads the beginnings of your JS app/view
- Access to all react-bootstrap components