DEV Community

Cover image for NextJS, Bootstrap 5 : an in-depth tutorial
David Boureau
David Boureau

Posted on • Originally published at bootiful.org

NextJS, Bootstrap 5 : an in-depth tutorial

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Now open the browser at the indicated URL (here http://localhost:3000)

NextJS default web page

NextJS default web page

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

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 :

Unstyled bootstrap content

Unstyled bootstrap content

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

And import Bootstrap as follow

// inside styles/application.scss
@import 'bootstrap/scss/bootstrap.scss';
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Relaunch your local server :

$/next-raw-bootstrap> yarn dev
Enter fullscreen mode Exit fullscreen mode

and open your browser at localhost:3000

Bootstrap, style only

Bootstrap, style only

Ok ! The application uses now Bootstrap 5 to style the application, but

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
  )

Enter fullscreen mode Exit fullscreen mode

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.

Bootstrap, collapsible navbar

Bootstrap, collapsible navbar

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
  )
Enter fullscreen mode Exit fullscreen mode

Let's check your local server is running, if not run

$/next-raw-bootstrap> yarn dev
Enter fullscreen mode Exit fullscreen mode

And reload your browser :

Bootstrap, toast message

Bootstrap, toast message

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';
Enter fullscreen mode Exit fullscreen mode

Let's see how the app is displayed now :

Bootstrap, bold message

Bootstrap, custom lead font

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

Run your local server with yarn dev and let's see how the default page is styled :

Bootstrap, simple message

Bootstrap, simple message

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
Enter fullscreen mode Exit fullscreen mode

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>
  )
}
Enter fullscreen mode Exit fullscreen mode

Bootstrap, accordion component

Bootstrap, accordion component

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

Discussion (0)