The Utility API
Every utility class TrailMap uses — .mt-3, .text-primary,
.d-flex, .rounded — isn't written out by hand in Bootstrap's source
as hundreds of individual CSS rules. It's generated from a single Sass map called
$utilities, where each entry describes one utility group: what the class prefix
is, which CSS property it sets, and what values it accepts. This generation system is what
Bootstrap calls the Utility API, and once you can read that map, you can add
your own utilities or delete ones TrailMap never uses — all without writing a single
hand-rolled CSS rule.
How the Utility API Works
Simplified, the entry that produces every .text-* color class looks like this
inside Bootstrap's own _utilities.scss:
"color": (
property: color,
class: text,
values: map-merge(
$theme-colors,
("body": $body-color)
)
)
Read as: "for the utility group named color, set the CSS property
color, using the class prefix text-, for every value in
$theme-colors." Bootstrap loops over that one entry and emits
.text-primary, .text-secondary, .text-success, and so
on — one map entry, dozens of generated classes.
Adding a Custom Utility
To add a class Bootstrap doesn't ship, TrailMap merges its own entry into the map using Sass's
map-merge, in the same trailmap-custom.scss entry file from the
previous lesson — variables and utility additions live before the same
@import "bootstrap/scss/bootstrap" line:
// trailmap-custom.scss
$primary: #2c7a4b;
// add a letter-spacing utility Bootstrap doesn't ship
$utilities: map-merge(
$utilities,
(
"letter-spacing": (
property: letter-spacing,
class: ls,
values: (
0: 0,
1: .05em,
2: .1em
)
)
)
);
@import "bootstrap/scss/bootstrap";
That produces three new classes — .ls-0, .ls-1, .ls-2 —
usable exactly like any built-in utility:
<span class="badge bg-primary ls-2">NEW TRAIL</span>
Removing Utilities You Never Use
The full utility set compiles into a lot of CSS. If TrailMap never uses Bootstrap's float
utilities (.float-start, .float-end) because everything is laid out
with flex and grid, they can be deleted from the map entirely before compiling, shrinking the
final CSS file:
// remove utility groups TrailMap never uses
$utilities: map-remove($utilities, "float");
@import "bootstrap/scss/bootstrap";
Worked Example: A .rounded-xl Utility for TrailMap Cards
Bootstrap's built-in .rounded utilities top out at a fairly modest radius.
TrailMap's trail-photo cards want a noticeably rounder corner, so instead of writing one-off
CSS, the border-radius group gets an extra value merged in:
// extend the existing "border-radius" utility group
$utilities: map-merge(
$utilities,
(
"rounded": map-merge(
map-get($utilities, "rounded"),
(
values: map-merge(
map-get(map-get($utilities, "rounded"), "values"),
("xl": 1rem)
)
)
)
)
);
@import "bootstrap/scss/bootstrap";
<div class="card rounded-xl">
<img src="eagle-ridge.jpg" class="card-img-top rounded-xl" alt="Eagle Ridge Trail">
<div class="card-body">
<h5 class="card-title">Eagle Ridge Trail</h5>
</div>
</div>
.rounded-xl now works anywhere .rounded or .rounded-lg
would — it's a real, ordinary utility class, generated the exact same way Bootstrap generates
its own.