Use Bootstrap with Astro
Dominik Rüttiger

Modern web development is based on components, whether or not a front-end framework like Angular or React is used. Combined with wide browser support for CSS variables, I would argue that it has never been easier to style using plain CSS.
With that out of the way, Bootstrap is still one of the most popular CSS frameworks and here is how to use it with Astro.
TL;DR
You can find the final result in this GitHub repository.
It includes a Dev Container configuration with all requirements.
Create a new Astro project
We start with a fresh Astro project:
npm create astro@latest -- --template minimal
Add Bootstrap npm packages
Install the following packages:
npm install bootstrap sassnpm install --save-dev @types/bootstrap
Add Bootstrap CSS styles
The key to using Bootstrap efficiently is to include only the CSS you need. Create a new Sass file that imports the necessary packages:
// Required functions import@import 'bootstrap/scss/functions';
// Optional variable overrides$primary: #ffa500;
// Required imports@import 'bootstrap/scss/variables';@import 'bootstrap/scss/variables-dark';@import 'bootstrap/scss/maps';@import 'bootstrap/scss/mixins';@import 'bootstrap/scss/root';
// Optional components@import 'bootstrap/scss/utilities';@import 'bootstrap/scss/reboot';@import 'bootstrap/scss/type';@import 'bootstrap/scss/containers';@import 'bootstrap/scss/images';@import 'bootstrap/scss/nav';// @import 'bootstrap/scss/accordion';// @import 'bootstrap/scss/alert';// @import 'bootstrap/scss/badge';// @import 'bootstrap/scss/breadcrumb';// @import 'bootstrap/scss/button-group';// @import 'bootstrap/scss/buttons';// @import 'bootstrap/scss/card';// @import 'bootstrap/scss/carousel';// @import 'bootstrap/scss/close';// @import 'bootstrap/scss/dropdown';// @import 'bootstrap/scss/forms';// @import 'bootstrap/scss/grid';// @import 'bootstrap/scss/list-group';// @import 'bootstrap/scss/modal';// @import 'bootstrap/scss/navbar';// @import 'bootstrap/scss/offcanvas';// @import 'bootstrap/scss/pagination';// @import 'bootstrap/scss/placeholders';// @import 'bootstrap/scss/popover';// @import 'bootstrap/scss/progress';// @import 'bootstrap/scss/spinners';// @import 'bootstrap/scss/tables';// @import 'bootstrap/scss/toasts';// @import 'bootstrap/scss/tooltip';// @import 'bootstrap/scss/transitions';
// Optional helpers// @import 'bootstrap/scss/helpers';
// Optional utilities@import 'bootstrap/scss/utilities/api';
During development or debugging, you could also temporarily import everything with:
// Optional variable overrides$primary: #ffa500;
// Import everything@import 'bootstrap/scss/bootstrap';
For more details, see the Sass page in the official Bootstrap documentation.
Add Layout and pages
Create a new Astro file that will serve as the main page layout. Same as with CSS, make sure you import only the JavaScript modules that you need:
---import '../styles/bootstrap.scss';---
<!doctype html><html lang="en" data-bs-theme="dark"> <head> <meta charset="utf-8" /> <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="generator" content={Astro.generator} /> <title>Bootstrap with Astro</title> <meta name="description" content="Use Bootstrap with Astro" /> </head> <body> <slot /> <script> // Import only what you need // import 'bootstrap/js/dist/alert'; // import 'bootstrap/js/dist/button'; // import 'bootstrap/js/dist/carousel'; // import 'bootstrap/js/dist/collapse'; // import 'bootstrap/js/dist/dropdown'; // import 'bootstrap/js/dist/modal'; // import 'bootstrap/js/dist/offcanvas'; // import 'bootstrap/js/dist/popover'; // import 'bootstrap/js/dist/scrollspy'; // import 'bootstrap/js/dist/tab'; // import 'bootstrap/js/dist/toast'; // import 'bootstrap/js/dist/tooltip'; </script> </body></html>
During development or debugging, you could also temporarily import everything with:
// Import everythingimport 'bootstrap/dist/js/bootstrap';
To use the layout replace the contents of the index page with the following Bootstrap example content:
---import Layout from '../layouts/Layout.astro';---
<Layout> <div class="container"> <header class="d-flex justify-content-center py-3"> <ul class="nav nav-pills"> { ['Home', 'Features', 'Pricing', 'FAQs', 'About'].map((n, i) => ( <li class="nav-item"> <a href="#" class:list={['nav-link', { active: i === 0 }, {'text-black': i === 0}]}>{n}</a> </li> )) } </ul> </header> <main class="text-center"> <h1 class="display-1">Hi Bootstrap!</h1> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-rocket-takeoff mt-5 img-fluid" style="width: 20rem; height: 20rem;" viewBox="0 0 16 16"> <path d="M9.752 6.193c.599.6 1.73.437 2.528-.362s.96-1.932.362-2.531c-.599-.6-1.73-.438-2.528.361-.798.8-.96 1.933-.362 2.532"/> <path d="M15.811 3.312c-.363 1.534-1.334 3.626-3.64 6.218l-.24 2.408a2.56 2.56 0 0 1-.732 1.526L8.817 15.85a.51.51 0 0 1-.867-.434l.27-1.899c.04-.28-.013-.593-.131-.956a9 9 0 0 0-.249-.657l-.082-.202c-.815-.197-1.578-.662-2.191-1.277-.614-.615-1.079-1.379-1.275-2.195l-.203-.083a10 10 0 0 0-.655-.248c-.363-.119-.675-.172-.955-.132l-1.896.27A.51.51 0 0 1 .15 7.17l2.382-2.386c.41-.41.947-.67 1.524-.734h.006l2.4-.238C9.005 1.55 11.087.582 12.623.208c.89-.217 1.59-.232 2.08-.188.244.023.435.06.57.093q.1.026.16.045c.184.06.279.13.351.295l.029.073a3.5 3.5 0 0 1 .157.721c.055.485.051 1.178-.159 2.065m-4.828 7.475.04-.04-.107 1.081a1.54 1.54 0 0 1-.44.913l-1.298 1.3.054-.38c.072-.506-.034-.993-.172-1.418a9 9 0 0 0-.164-.45c.738-.065 1.462-.38 2.087-1.006M5.205 5c-.625.626-.94 1.351-1.004 2.09a9 9 0 0 0-.45-.164c-.424-.138-.91-.244-1.416-.172l-.38.054 1.3-1.3c.245-.246.566-.401.91-.44l1.08-.107zm9.406-3.961c-.38-.034-.967-.027-1.746.163-1.558.38-3.917 1.496-6.937 4.521-.62.62-.799 1.34-.687 2.051.107.676.483 1.362 1.048 1.928.564.565 1.25.941 1.924 1.049.71.112 1.429-.067 2.048-.688 3.079-3.083 4.192-5.444 4.556-6.987.183-.771.18-1.345.138-1.713a3 3 0 0 0-.045-.283 3 3 0 0 0-.3-.041Z"/> <path d="M7.009 12.139a7.6 7.6 0 0 1-1.804-1.352A7.6 7.6 0 0 1 3.794 8.86c-1.102.992-1.965 5.054-1.839 5.18.125.126 3.936-.896 5.054-1.902Z"/> </svg> </main> </div></Layout>
Add more pages using the same <Layout>
if you like.
Bootstrap icons
There are many options to include icons. I recommend to use the official Bootstrap Icons and add the SVG directly to the Astro/HTML files.
Just head over to their docs, select an icon that you like, copy the SVG and paste it into your page. No need to overcomplicate things.
Run the development server
To check the final result run:
npm run dev
Running in production
Only including the CSS and JavaScript that we need, and without any further optimization, the Lighthouse score rocks!
This setup can be optimized even more. But don’t overdo it. Simplicity is king.
Set caching header
All files in the dist/_astro
folder are compiled by Astro and an hash is
included in the file name. If the content changes the filename will change, too.
Therefore we can tell the browser that it is safe to cache these files forever. The browser will not even check if there is a new version, making subsequent page visits blazingly fast.
For the classic Apache webserver that many hosters still use, this can easily be configured by creating the following file:
<FilesMatch "\.(css|js|webp|jpg|jpeg|png|svg)$"> Header set Cache-Control "max-age=31536000"</FilesMatch>
Minimize CSS
If you had been exposed to Tailwind for a long time, you will feel the urge to minify Bootstrap’s CSS. This is totally possible to do, and can easily be automated with the astro-purgecss integration .
But in my opinion, it is not worth bringing in a new dependency to your project. The compiled Bootstrap CSS file is usually really small:
- The example we build: 12 kB
- The medium-size website I made for my foosball club: 23 kB
This is nothing compared the megabytes of web bloat these days.
Tags
#astro #bootstrap #css #webperformance