Article originally published here : https://bootiful.org/blog/nextjs-bootstrap
Today we'll see how to install, customize, and use dynamic component of Bootstrap 5 with NextJS.
First, let's see how to use Bootstrap 5 with NextJS, without using any 3rd party library (other than Bootstrap itself, of course). At the end of the article, we will see other way to do it.
Prerequisite : node, yarn
For this tutorial, NodeJS is required, and you can use yarn or npm as you wish, but yarn will be used here.
$> node --version
v14.15.1
$> yarn --version
1.22.10
It should not be a problem if you have slightly different versions.
Create a fresh new NextJS app
Some kind of magic now : the creation of a default NextJS app is embedded into the yarn executable
$> yarn create next-app next-raw-bootstrap
Press Enter, a new app is magically building files, directory, and first few dependencies for you.
Notice that next-raw-bootstrap
is the name of your new app - I used "raw" here to emphasize that we will use Bootstrap only.
Now go to the "next-raw-bootstrap" directory and open your favorite code editor at the root of "next-raw-bootstrap".
$> cd next-raw-bootstrap
You can have a look to the directory structure and the created files, particularly package.json : very few dependencies, but already everything needed to lint and hot-reload code locally. Nice !
$/next-raw-bootstrap> yarn dev
yarn run v1.22.10
$ next dev
**ready** - started server on http://localhost:3000
Now open the browser at the indicated URL (here http://localhost:3000)
NextJS default website should now appear in your browser. There is a few CSS styles, and a default index page (what you can see by default is under pages/index.js
)
Bootstrap 5 HTML : a not too easy sample
Now go to pages/index.js
, delete all existing content, and replace by this one :
import Head from 'next/head'
export default function Home() {
return (
<div>
<Head>
<title>Next and Bootstrap</title>
<meta name="description" content="A demo about NextJS and Bootstrap 5" />
</Head>
<div className="toast align-items-center text-white bg-primary border-0 position-absolute top-50" role="alert" aria-live="assertive" aria-atomic="true">
<div className="d-flex">
<div className="toast-body">
Hello, world! This is a toast message.
</div>
<button type="button" className="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
<div className="collapse" id="navbarToggleExternalContent">
<div className="bg-dark p-4">
<h5 className="text-white h4">Collapsed content</h5>
<span className="text-muted">Toggleable via the navbar brand.</span>
</div>
</div>
<nav className="navbar navbar-dark bg-dark">
<div className="container-fluid">
<button className="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarToggleExternalContent" aria-controls="navbarToggleExternalContent" aria-expanded="false" aria-label="Toggle navigation">
<span className="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<main>
<section className="py-5 text-center container">
<div className="row py-lg-5">
<div className="col-lg-6 col-md-8 mx-auto">
<h1 className="fw-light">Bootstrap 5.1.3 example</h1>
<p className="lead text-muted">Short text.</p>
</div>
</div>
</section>
</main>
</div>
)
}
The example is quite simple, but also complex enough to show how dynamic component should work.
Here is what you should see in the browser :
Add SaSS to allow Bootstrap customisation
CSS alone might not be enough for a production-ready project. SaSS allow to define variables, functions, and a bunch of features above CSS to allow you a long-term, maintainable CSS design system.
And good news : Bootstrap source files are based on SaSS.
Stop the local server. And type :
$/next-raw-bootstrap> yarn add -D sass@1.43.5
Side note The "-D" option here means that sass will be used in development mode only. Some dependencies are needed only during development time, like linting, other only on build time, like building CSS with SaSS. All dependencies that will not end up in the browser can be safely put inside the development section of your package.json file.
Get Bootstrap and NextJS working together (styling only)
Now that SaSS is installed, let's install bootstrap and it's required JS dependency PopperJS :
$/next-raw-bootstrap> yarn add @popperjs/core@2.11.0
$/next-raw-bootstrap> yarn add bootstrap@5.1.3
Now check your package.json file
{
"name": "next-raw-bootstrap",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@popperjs/core": "2.11.0",
"bootstrap": "5.1.3",
"next": "12.0.4",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"eslint": "7",
"eslint-config-next": "12.0.4",
"sass": "1.43.5"
}
}
You should now see "popper" and "bootstrap" inside the dependencies, and "sass" inside the devDependencies.
Now add an application.scss file (scss in the extension for SaSS files) here : styles/application.scss
$/next-raw-bootstrap> touch styles/applications.scss
And import Bootstrap as follow
// inside styles/application.scss
@import 'bootstrap/scss/bootstrap.scss';
And import this application.scss into your _app (you can safely remove other styles) :
// inside pages/_app.js
import '../styles/application.scss'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
Relaunch your local server :
$/next-raw-bootstrap> yarn dev
and open your browser at localhost:3000
Ok ! The application uses now Bootstrap 5 to style the application, but
- The navigation button (hamburger menu) does not work
- The Toast is not showing (as if it's in the HTML). Bootstrap do not display Toast messages by default, you have to trigger it manually. (see https://getbootstrap.com/docs/5.1/components/toasts/)
JavaScript of Bootstrap within NextJS
Contrary to Tailwind, Bootstrap is not only a CSS framework and a design system. It comes also with a bunch of dynamic components like collapsible navigation bar (also called "navbar"), toasts messages, and so on. CSS is not really able to bring this "dynamic" part. But this is precisely why Bootstrap sometimes needs JavaScript to get every feature working properly.
Some component like the collapsible navbar doesn't need anything else but loading the whole bootstrap JS library.
Let's change the top part of pages/index.js (returned HTML stay the same)
// pages/index.js, returned HTML is unchanged
import React, { useEffect } from "react";
import Head from 'next/head'
export default function Home() {
// See https://en.reactjs.org/docs/hooks-effect.html
useEffect(() => {
// Run code on client-side only : ensure document is here
if (typeof document !== undefined) {
// load JS bootstrap dependency
require('bootstrap/dist/js/bootstrap')
}
// Run useEffect only once
// Read https://css-tricks.com/run-useeffect-only-once/
}, [])
return (
// same HTML as before
)
We use here a hook (callback inside useEffect) to modify the DOM once it has properly loaded. We check that the document exists (which means that we are working client-side, inside the browser, and not server side), and once all conditions are met, the Bootstrap's JS lib is loaded from node_modules.
Reload the page in your browser.
Great ! If you click on the hamburger menu, you will now see that the component works properly.
But... the toast message is still not displayed.
Bootstrap JavaScript-based initialization within NextJS
So we have now some of the Bootstrap JavaScript components that works. The ones that doesn't require any special initialization. However, some components like toast messages (https://getbootstrap.com/docs/5.1/components/toasts/) need to be manually triggered. Let's see how.
// pages/index.js, returned HTML is unchanged
import React, { useEffect } from "react";
import Head from 'next/head'
export default function Home() {
// See https://en.reactjs.org/docs/hooks-effect.html
useEffect(() => {
// Run code on client-side only : ensure document is here
if (typeof document !== undefined) {
// load JS bootstrap dependency
let bootstrap = require('bootstrap/dist/js/bootstrap')
// find all toasts
let toastElList = [].slice.call(document.querySelectorAll('.toast'))
let toastList = toastElList.map(function (toastEl) {
return new bootstrap.Toast(toastEl)
})
// show each toast explicitly
toastList.forEach( function(element, index) {
element.show()
})
}
// Run useEffect only once
// Read https://css-tricks.com/run-useeffect-only-once/
}, [])
return (
// same HTML as before
)
Let's check your local server is running, if not run
$/next-raw-bootstrap> yarn dev
And reload your browser :
Ta-da ! Now the Toast message is displayed.
Customize Bootstrap style for a NextJS app
Ok, now both CSS and JS work for Bootstrap inside a NextJS app, let's see how to customize Bootstrap, in order to maintain a coherent
// inside styles/application.scss
$lead-font-size: 5rem;
$lead-font-weight: 800;
@import 'bootstrap/scss/bootstrap.scss';
Let's see how the app is displayed now :
As you can see, Bootstrap ".lead" class has been changed, just by changing SaSS variables. In Bootstrap 5 there are a lot of variables. All the variable you can set are available here :
https://github.com/twbs/bootstrap/blob/v5.1.3/scss/_variables.scss
Show me the code, please
Final code source for this first part can be seen here : https://github.com/bdavidxyz/next-raw-bootstrap
Restart from scratch, with Bootstrap 5 components
Why would you restart from scratch ? Let's admit it : use Bootstrap 5 "as is" inside a NextJS is not very elegant. Because ReactJS is about components. Wouldn't it be nice if the Bootstrap components were already wrapped somewhere into React components ?
Good news : it has already been made here :
https://github.com/react-bootstrap/react-bootstrap
Side note There are two similar projects : react-bootstrap and reactstrap. They slightly differ in the way components are coded, but are very similar when you use them. So pick your favorite. I personally find react-bootstrap more complete, so for this tutorial we will use react-bootstrap.
(Re)create a fresh new NextJS app
$> yarn create next-app next-bootstrap
$> cd next-bootstrap
$/next-bootstrap> yarn add -D sass@1.43.5
$/next-bootstrap> yarn add @popperjs/core@2.11.0
$/next-bootstrap> yarn add bootstrap@5.1.3
$/next-bootstrap> echo "@import 'bootstrap/scss/bootstrap.scss';" > styles/application.scss
Then make sure that pages/_app is importing application.scss :
// pages/_app.js
import '../styles/application.scss'
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
So far, nothing new.
One last thing : modify pages/index.js as follow :
import Head from 'next/head'
export default function Home() {
return (
<div>
<Head>
<title>NextJS app with react-bootstrap</title>
</Head>
<main>
<h1>
Welcome
</h1>
</main>
</div>
)
}
Run your local server with yarn dev
and let's see how the default page is styled :
Ok ! Now it's type to see the magic of React components
React-based Bootstrap components thanks to react-bootstrap
$/next-bootstrap> yarn add react-bootstrap@2.0.3
And change pages/index.js
as follow :
import Head from 'next/head'
import {Accordion} from 'react-bootstrap'
export default function Home() {
return (
<div>
<Head>
<title>NextJS app with react-bootstrap</title>
</Head>
<main>
<h1>
Welcome
</h1>
<Accordion defaultActiveKey="0">
<Accordion.Item eventKey="0">
<Accordion.Header>Accordion Item #1</Accordion.Header>
<Accordion.Body>
Lorem ipsum dolor sit amet...
</Accordion.Body>
</Accordion.Item>
<Accordion.Item eventKey="1">
<Accordion.Header>Accordion Item #2</Accordion.Header>
<Accordion.Body>
Duis aute irure dolor in reprehenderit in voluptate...
</Accordion.Body>
</Accordion.Item>
</Accordion>
</main>
</div>
)
}
click on the accordion to see how the UX flows...
Nice ! Instead of manually pull the JS Bootstrap lib inside a useEffect hook, we simply imported here the component, this is a lot more intuitive.
Code for this last example
https://github.com/bdavidxyz/next-bootstrap
Credits
NextJS documentation : https://nextjs.org/docs
Bootstrap documentation : https://getbootstrap.com/docs/5.1/
React-Bootstrap repository : https://github.com/react-bootstrap/react-bootstrap
Top comments (0)