Speedy and Stylish - How to style NextJS with Bootstrap 5, SASS, and PurgeCSS

Speedy and Stylish - How to style NextJS with Bootstrap 5, SASS, and PurgeCSS

A quick and easy how-to for styling Next apps in 2021

Quick how-to for you today. I'm setting up a new web app project with these parameters:

  • I want it to be based on Next.JS because it's my favorite React framework.
  • I want to style it with Bootstrap 5 because I need more help setting up a consistent theme than Tailwind would give me.
  • I want to write the styles in SASS because that's what Bootstrap uses under the hood, which makes customizing the Bootstrap theme easier.
  • I want to run the styling through PurgeCSS to avoid shipping unnecessary Bootstrap bloat.

So how do you do that?

1. NextJS

Setting up a new NextJS project is foolishly easy. First, pick an example to base your project on. I personally chose with-typescript-eslint-jest because I like writing in Typescript much more than vanilla JS and I like having ESLint in VSCode to automatically style my files when I hit save.

Second, run one of these (depending on whether you want to use npm or yarn), substituting in your chosen example template and replacing your-project with the name for your project:

npx create-next-app -e with-typescript-eslint-jest your-project
yarn create next-app -e with-typescript-eslint-jest your-project

Note that from here onward I'll be writing everything in yarn commands, so be sure to substitute npm if that's what you're using.

And that's it, you're done. You have a basic Next.JS app ready to go. Start it up with yarn dev and see your site running at http://localhost:3000.

2. Bootstrap 5 in SASS

Next, let's add Bootstrap 5. If you want just a few Bootstrap elements, you can get away with using the react-bootstrap package. Their 2.0 build (based on Bootstrap 5) is in beta release right now. But, I want to build larger, more personalized themes, so I'm going to install Bootstrap directly.

yarn add bootstrap@^5.0.1

This will add Bootstrap's raw source to your node_modules. Now Bootstrap has two parts to it - the styling and the javascript - that combine to create the pretty and pretty functional components.

First, let's add the styling. We're going to write our styles in SASS because it allows us to extend and override values in Bootstrap's themes. You can read more about customizing Bootstrap in SASS here.

Luckily, NextJS ships with built-in support for SASS. So it's as easy as adding the sass package and creating styles/index.scss:

yarn add sass
// Example: override to give us a salmon body background
$body-bg: #ffbbbb;

@import "../node_modules/bootstrap/scss/bootstrap";

and then importing it in pages/_app.tsx:

import type { AppProps } from "next/app";
import "../../styles/index.scss";

export default function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

Refresh your development site and you should find the basic Bootstrap "reboot" styles are applied and the background is now a nice salmon color.

Next, the Javascript. We only have to do this if we use one of the dynamic components like Alert. If so, we first have to install the popper dependency:

yarn add @popperjs/core

Then, we use Bootstrap's recommendations on importing their JS into a Webpack environment. In _app.tsx pick one of these:

// If you want to pull in the whole Bootstrap JS library:
import "bootstrap";

// If you only need a single component:
import Alert from "bootstrap/js/dist/alert";

These each tell Webpack to include the relevant source file(s) in the final bundle it makes when we build our app for production or export.

3. Keep it trim with PurgeCSS

One of the advantages of TailwindCSS over Bootstrap has been that it automatically trims out the bloat of the framework that you don't use, so you don't wind up shipping styling for <table> elements if you don't use any on your site. It accomplishes this through PurgeCSS, which is trivial for it because it is based on PostCSS and dynamic style generation in the first place.

NextJS ships with PostCSS already, so we can give Bootstrap this same superpower by adding PurgeCSS to Next. Unfortunately, as the PurgeCSS page on this notes, customizing PostCSS turns off NextJS's built in optimizations, so we have to recreate them. Luckily, this isn't hard. First, install the packages we need:

yarn add -D autoprefixer postcss @fullhuman/postcss-purgecss postcss-flexbugs-fixes postcss-preset-env

Now that the pieces are in place, we put them all into our build pipeline by creating a custom postcss.config.js file in our project's root folder:

module.exports = {
  plugins: [
    "postcss-flexbugs-fixes",
    [
      "postcss-preset-env",
      {
        autoprefixer: { flexbox: "no-2009" },
        stage: 3,
        features: { "custom-properties": false }
      }
    ],
    [
      "@fullhuman/postcss-purgecss",
      {
        content: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],
        defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
        safelist: ["html", "body"]
      }
    ]
  ]
};

The first half of this file is pulled directly from NextJS's documentation on customizing PostCSS. The second half adds in PurgeCSS and configures it to remove all classes whose names do not appear in the src or pages directories. It also tells it to manually to leave any html or body styles alone, since those two elements are rendered outside of the scope of our Next project's source files.

Ok, so refresh your local dev build again and... nothing changes! This is intentional - PurgeCSS shouldn't be purging any classes that are used. This also includes the styles we need in Reboot - Bootstrap's cross-browser standardizing stylesheet. If we use an element type that Reboot standardizes, then PurgeCSS will recognize that and won't touch the corresponding style.

That's it but...

There you go - an easy 1, 2, 3 and now you have a new NextJS project set up with efficiently and intelligently trimmed-down Bootstrap 5 styling. Hope this is helpful for you while you're setting up a project.

However, before I go there is one big caveat I have to leave you with:

Next's fast refresh feature calculates what needs to be rebuilt based on what files changed. The unfortunate thing here is that, because PurgeCSS means that our styles might need to change if our JS/TS source files change, we now can wind up with missing styles in development mode - Next won't recompute the styles unless the styles themselves change! There must be a way around this, but I haven't figured it out yet. My solution is that I have the PurgeCSS config commented out in development and then add it back in for production. If you know how to fix this, though, please let me know down in the comments!

Did you find this article valuable?

Support Zack Sheppard by becoming a sponsor. Any amount is appreciated!