- Jun 4, 2024
How to Customize Bootstrap 5 in a Blazor application
When creating a new Blazor application from the default template, you get a project that is pre-configured with Bootstrap 5. You can add your own styles, but you can't easily customize the default Bootstrap settings.
That's what I will show you how to do today.
Getting started with the default template
I'm going to start by creating a sample project for an application that will serve as a common use case throughout my content. It's a web application called Outcome Studio, and will allow users to identify the right products to build, by gathering customer information, building a job map using the Jobs-to-be-Done framework and refining it using several product discovery techniques.
I already have an empty repo, so the first step is to create the solution and the project. For reference, I'm using the 8.0.301 SDK and 806 runtime.
dotnet new solution -n OutcomeStudio
dotnet new blazor -n OutcomeStudio.WebApp -o src -int AutoYou'll note that I'm using Auto as the render mode. This is optional, but I know I'll need it in the future, so I went ahead and added it now. Using this option creates two projects (server side and client side) and its own solution file, so the next step is to fix that.
rm src/OutcomeStudio.WebApp.sln
dotnet sln add src/OutcomeStudio.WebApp/OutcomeStudio.WebApp.csproj
dotnet sln add src/OutcomeStudio.WebApp.Client/OutcomeStudio.WebApp.Client.csprojYou can run the project now and this is what you should see.
Deleting the existing Bootstrap 5
The first step is to remove the Bootstrap 5 version that comes with the template. Just delete the whole bootstrap folder inside wwwroot in the WebApp project.
After that, we are ready to add it back. We could just add it from a CDN as is recommended in the Getting Started tutorial, but we are going to use a different method.
Enter LibMan
Since we want to customize it, we need to get the Sass files and compile them before including. The way to do it is with a tool called LibMan. From the documentation:
Library Manager (LibMan) is a lightweight, client-side library acquisition tool. LibMan downloads popular libraries and frameworks from the file system or from a content delivery network (CDN). The supported CDNs include CDNJS, jsDelivr, and unpkg. The selected library files are fetched and placed in the appropriate location within the ASP.NET Core project.
You can install LibMan as a global tool with the following command:
dotnet tool install -g Microsoft.Web.LibraryManager.CliAgain, for reference, I'm using version 2.1.175. After that, you need to initialize it locally. There are a couple of options worth mentioning:
Since I'm using Libman mostly for Bootstrap, I just make jsDelivr the default provider.
You can choose the default destination for the files, either a project folder (like
wwwroot) or a separate folder. Personally, I prefer to install the files on a separatelibfolder, because I can control better which files I need to depend on and I just add the folder to .gitignore. However, I want it to be per-library instead, so I set the destination when installing each library.
libman init -p jsdelivrYou're ready to install Bootstrap (currently 5.2.3)
libman install bootstrap@5.2.3 -d lib/bootstrapHere's what you should see right now:
In order to test that this is working, just copy the file lib/bootstrap/dist/css/bootstrap.min.css manually to wwwroot, and change App.razor to include the correct file.
<link rel="stylesheet" href="bootstrap.min.css" />You can also copy bootstrap.min.css.map, but it's not needed as we will automate this soon.
Note: You can't link those files by adding "Existing item" into
wwwroot. While this will work when you publish the project, it doesn't work withdotnet run. See this Github issue.
If you run the application again, you'll see that everything is working.
Customizing Bootstrap with SCSS
To properly customize Bootstrap, we will create a Sass file where we will import the core files and add all the original template CSS. This way, you can modify the styles as needed without changing any of the original Bootstrap files. In addition to that, you can take advantage of all the variables, maps, and mixins.
To keep things simple, we're going to include all of Bootstrap, but you also have the option to include only parts, as shown here, although we will use a slightly different structure. To get started, add an app.scss file in the wwwroot folder, with the following code:
// 1. Include functions first (so you can manipulate colors, SVGs, calc, etc)
@import "../../../lib/bootstrap/scss/functions";
// 2. Include any default variable overrides here
// We will add customizations here
// 3. Import the rest of bootstrap
@import "../../../lib/bootstrap/scss/bootstrap";
// 4. Add additional custom code here
// Copy the styes from the original app.css file and delete app.cssSince we will only have one CSS file for now, remove from App.razor the link to bootstrap.min.css and leave only app.css.
Compiling SCSS to CSS
If you run the application now, you'll see that you don't have styles. The reason for this is that we're missing a critical step: take the SCSS file and generate the corresponding CSS file. This is where the solution will depend on your environment, in particular on the IDE you use. I use JetBrains Rider and it uses File Watchers to handle this. Just follow the instructions on this page and you will be set. The defaults will be enough to convert your SCSS into a pair of CSS and CSS map files, in the same folder, with the same relative names.
Note: the "Project Files" scope was not working correctly for me ("Unknown scope"), but you can change to "All Changed Files" and it will work either way.
To test that this is working, let's change the primary color and use it in the buttons. Open the app.scss file and add $primary: hsl(265, 65%, 35%); under section 2. for the default variable overrides.
If you run the application now and go to the Counter page, you'll see an odd behavior. The color of the button is still the same. However, if you hover the button, you'll see the correct color, slightly darker than the primary color we defined.
If you look at the original CSS in app.scss, you'll see in line ~20 the .btn-primary class. This highlights the main advantage of customizing Bootstrap this way: you don't have to rewrite the classes everywhere.
So, you can remove that .btn-primary class and start the application again. This time, you'll see the correct colors.
Bonus: Optimized CSS
Just like compiling SCSS to CSS, in order minify your code automatically using JetBrains Rider, you need to add another File Watcher using CSSO. You can see how to do that in this page, but it's trivial like before. As soon as you save your SCSS file, the CSS file is generated and then minified.
The only thing left to do is to change you App.razor file to use the new min.css file instead.
<link rel="stylesheet" href="app.min.css" />