Bootstrap utilities are generated with our utility API and can be used to modify or extend our default set of utility classes via Sass. Our utility API is based on a series of Sass maps and functions for generating families of classes with various options. If you’re unfamiliar with Sass maps, read up on the official Sass docs to get started.
The $utilities map contains all our utilities and is later merged with your custom $utilities map, if present. The utility map contains a keyed list of utility groups which accept the following options:
| Option | Type | Default value | Description |
|---|---|---|---|
property | Required | – | Name of the property. Can be a string, a space-separated list of strings (e.g., horizontal paddings or margins), or a map of property-to-default-value pairs (see Property-Value Mapping). |
values | Required | – | List of values, or a map if you don’t want the class name to be the same as the value. If null is used as map key, class is not prepended to the class name. |
selector | Optional | class | Type of CSS selector in the generated CSS ruleset. Can be class, attr-starts, or attr-includes. |
child-selector | Optional | null | A child/descendant selector appended to the utility’s selector, wrapped in :where() for zero specificity. Use to target children instead of the element itself. |
class | Optional | null | Name of the generated class. If not provided and property is an array of strings, class will default to the first element of the property array. If not provided and property is a string, the values keys are used for the class names. |
variables | Optional | null | List or map of CSS custom properties to generate within each utility class. When a list, each variable receives the utility value. When a map, the provided static values are used. |
state | Optional | null | List of pseudo-class variants (e.g., :hover or :focus) to generate as prefix-style classes. |
responsive | Optional | false | Boolean indicating if responsive classes should be generated. |
important | Optional | false | Boolean indicating if !important should be added to the utility’s CSS rules. |
print | Optional | false | Boolean indicating if print classes need to be generated. |
dark | Optional | false | Boolean indicating if dark: prefixed classes should be generated, scoped to @media (prefers-color-scheme: dark). |
enabled | Optional | true | Set to false to suppress output for a utility while keeping its definition in the $utilities map. |
API explained
All utility variables are added to the $utilities variable within our _utilities.scss stylesheet, which is a giant, nested Sass map. Each group of utility classes are generated from a block that looks something like this:
$utilities: (
"opacity": (
property: opacity,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);Which outputs the following:
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }property
The property key must be set for any utility, and it must contain a valid CSS property. This property is used in the generated utility’s ruleset. When the class key is omitted, it also serves as the default class name. Consider the text-decoration utility:
$utilities: (
"text-decoration": (
property: text-decoration,
values: none underline line-through
)
);Output:
.text-decoration-none { text-decoration: none; }
.text-decoration-underline { text-decoration: underline; }
.text-decoration-line-through { text-decoration: line-through; }Property value mapping
The property key also accepts a map of CSS property names to default values. This lets a single utility class set multiple properties at once, and lets values override individual properties when the value is itself a map.
When a property's default value in the map is null, the utility value is used directly for that property. When a default value is set, it is used unless the utility's value map contains a matching key.
A common pattern is pairing a CSS custom property (which receives the utility value) with a regular property that references it:
$utilities: (
"bg-color": (
property: (
"--bg": null,
"background-color": var(--bg)
),
class: bg,
values: (
primary: var(--blue-500),
danger: var(--red-500),
)
)
);Output:
.bg-primary { --bs-bg: var(--bs-blue-500); background-color: var(--bs-bg); }
.bg-danger { --bs-bg: var(--bs-red-500); background-color: var(--bs-bg); }Source CSS variables are used without a --bs- prefix, which is added in our compiled CSS with our PostCSS plugin.
You can also set per-value overrides. When values contains a nested map whose keys match properties in the property map, those values are used for the matching property:
$utilities: (
"text-size": (
property: (
"font-size": 1rem,
"line-height": 1.5
),
class: text,
values: (
"sm": ("font-size": .875rem, "line-height": 1.25),
"lg": ("font-size": 1.25rem, "line-height": 1.75),
)
)
);Output:
.text-sm { font-size: .875rem; line-height: 1.25; }
.text-lg { font-size: 1.25rem; line-height: 1.75; }values
Use the values key to specify which values for the specified property should be used in the generated class names and rules. Can be a list or map (set in the utilities or in a Sass variable).
As a list, like with text-decoration utilities:
values: none underline line-throughAs a map, like with opacity utilities:
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)As a Sass variable that sets the list or map, as in our position utilities:
values: $position-valuesselector
| Option | Description |
|---|---|
| No selector | Defaults to "class" |
"class" | Matches elements with a class that matches the specified value |
"attr-starts" | Matches elements with a class that starts with a string |
"attr-includes" | Matches elements with a class that includes a string |
Use the selector option to change the CSS selector used in the generated CSS ruleset. The default option is to generate a class selector. When using an attribute selector—either attr-starts or attr-includes—the class option is required. We use these internally to simplify the construction of other utilities.
For attribute selectors, you’ll most likely want the attr-includes as the starting attribute selector in CSS applies to the entire string of classes in an attribute’s value. For example, [class^="name"] would not match class="example name".
As an example, to change from .ratio-* to [class*="ratio-"]:
$utilities: (
// Create an attribute selector utility
"aspect-ratio-attr": (
selector: "attr-includes",
class: "ratio-",
property: aspect-ratio,
values: var(--ratio),
),
// Create a CSS variable utility that matches the attribute selector utility
"aspect-ratio": (
property: --ratio,
class: ratio,
values: $aspect-ratios
),
);Note that the --ratio custom property will automatically be prefixed to --bs-ratio in the compiled CSS via PostCSS.
Which outputs the following:
[class*="ratio-"] { aspect-ratio: var(--bs-ratio); }
.ratio-auto { --bs-ratio: auto; }
.ratio-1x1 { --bs-ratio: 1 / 1; }
.ratio-4x3 { --bs-ratio: 4 / 3; }
.ratio-16x9 { --bs-ratio: 16 / 9; }
.ratio-21x9 { --bs-ratio: 21 / 9; }child-selector
Use the child-selector option to apply a CSS property to children of the element with the utility class rather than the element itself. The generated selector is wrapped in :where() for zero specificity, making it easy to override. This powers our built-in space-x/y and divide-x/y utilities.
For example, our space-x utility uses child-selector to add horizontal spacing between direct children:
$utilities: (
"space-x": (
property: margin-inline-end,
class: space-x,
child-selector: "> :not(:last-child)",
values: (
1: .25rem,
2: .5rem,
3: 1rem,
)
)
);Output:
:where(.space-x-1 > :not(:last-child)) { margin-inline-end: .25rem; }
:where(.space-x-2 > :not(:last-child)) { margin-inline-end: .5rem; }
:where(.space-x-3 > :not(:last-child)) { margin-inline-end: 1rem; }The child-selector value can be any valid CSS selector. For example, you could create a striped row utility using :nth-child():
$utilities: (
"striped-bg": (
property: background-color,
class: striped,
child-selector: "> :nth-child(odd)",
values: (
null: var(--bs-bg-1),
)
)
);Output:
:where(.striped > :nth-child(odd)) { background-color: var(--bs-bg-1); }Or target all direct children with > *:
$utilities: (
"child-rounded": (
property: border-radius,
class: child-rounded,
child-selector: "> *",
values: (
null: var(--bs-border-radius),
0: 0,
)
)
);Output:
:where(.child-rounded > *) { border-radius: var(--bs-border-radius); }
:where(.child-rounded-0 > *) { border-radius: 0; }class
Use the class option to change the class prefix used in the compiled CSS. For example, to change from .opacity-* to .o-*:
$utilities: (
"opacity": (
property: opacity,
class: o,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);Output:
.o-0 { opacity: 0; }
.o-25 { opacity: .25; }
.o-50 { opacity: .5; }
.o-75 { opacity: .75; }
.o-100 { opacity: 1; }If class: null, generates classes for each of the values keys:
$utilities: (
"visibility": (
property: visibility,
class: null,
values: (
visible: visible,
invisible: hidden,
)
)
);Output:
.visible { visibility: visible; }
.invisible { visibility: hidden; }Variables
Use the variables option to generate CSS custom properties within each utility class’s ruleset. The value can be either a list or a map.
When variables is a list, each variable receives the current utility value:
$utilities: (
"link-opacity": (
property: color,
class: link,
variables: link-color,
values: (
10: 10%,
50: 50%,
100: 100%,
)
),
);Output:
.link-10 { --bs-link-color: 10%; color: 10%; }
.link-50 { --bs-link-color: 50%; color: 50%; }
.link-100 { --bs-link-color: 100%; color: 100%; }When variables is a map, the provided static values are used on every generated class:
$utilities: (
"link-underline": (
property: text-decoration-color,
class: link-underline,
variables: (
"link-underline-opacity": 1
),
values: (...)
)
);Output:
.link-underline-primary {
--bs-link-underline-opacity: 1;
text-decoration-color: ...;
}States
Use the state option to generate pseudo-class variations. Example pseudo-classes are :hover and :focus. When a list of states are provided, classnames are created for that pseudo-class with a prefix-style syntax matching the responsive prefix pattern. For example, to change opacity on hover, add state: hover and you’ll get .hover\:opacity:hover in your compiled CSS.
Need multiple pseudo-classes? Use a space-separated list of states: state: hover focus.
$utilities: (
"opacity": (
property: opacity,
class: opacity,
state: hover,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);Output:
.hover\:opacity-0:hover { opacity: 0; }
.hover\:opacity-25:hover { opacity: .25; }
.hover\:opacity-50:hover { opacity: .5; }
.hover\:opacity-75:hover { opacity: .75; }
.hover\:opacity-100:hover { opacity: 1; }Responsive
Add the responsive boolean to generate responsive utilities (e.g., .md\:opacity-25) across all breakpoints.
$utilities: (
"opacity": (
property: opacity,
responsive: true,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);Output:
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }
@media (min-width: 576px) {
.sm\:opacity-0 { opacity: 0; }
.sm\:opacity-25 { opacity: .25; }
.sm\:opacity-50 { opacity: .5; }
.sm\:opacity-75 { opacity: .75; }
.sm\:opacity-100 { opacity: 1; }
}
@media (min-width: 768px) {
.md\:opacity-0 { opacity: 0; }
.md\:opacity-25 { opacity: .25; }
.md\:opacity-50 { opacity: .5; }
.md\:opacity-75 { opacity: .75; }
.md\:opacity-100 { opacity: 1; }
}
@media (min-width: 1024px) {
.lg\:opacity-0 { opacity: 0; }
.lg\:opacity-25 { opacity: .25; }
.lg\:opacity-50 { opacity: .5; }
.lg\:opacity-75 { opacity: .75; }
.lg\:opacity-100 { opacity: 1; }
}
@media (min-width: 1280px) {
.xl\:opacity-0 { opacity: 0; }
.xl\:opacity-25 { opacity: .25; }
.xl\:opacity-50 { opacity: .5; }
.xl\:opacity-75 { opacity: .75; }
.xl\:opacity-100 { opacity: 1; }
}
@media (min-width: 1536px) {
.\32 xl\:opacity-0 { opacity: 0; }
.\32 xl\:opacity-25 { opacity: .25; }
.\32 xl\:opacity-50 { opacity: .5; }
.\32 xl\:opacity-75 { opacity: .75; }
.\32 xl\:opacity-100 { opacity: 1; }
}Enabling the print option will also generate utility classes for print, which are only applied within the @media print { ... } media query.
$utilities: (
"opacity": (
property: opacity,
print: true,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);Output:
.opacity-0 { opacity: 0; }
.opacity-25 { opacity: .25; }
.opacity-50 { opacity: .5; }
.opacity-75 { opacity: .75; }
.opacity-100 { opacity: 1; }
@media print {
.print\:opacity-0 { opacity: 0; }
.print\:opacity-25 { opacity: .25; }
.print\:opacity-50 { opacity: .5; }
.print\:opacity-75 { opacity: .75; }
.print\:opacity-100 { opacity: 1; }
}Dark
Enabling the dark option generates dark: prefixed classes scoped to @media (prefers-color-scheme: dark). This follows the same prefix convention as responsive and print utilities.
$utilities: (
"bg-color": (
property: background-color,
class: bg,
dark: true,
values: (
white: #fff,
black: #000,
)
)
);Output:
.bg-white { background-color: #fff; }
.bg-black { background-color: #000; }
@media (prefers-color-scheme: dark) {
.dark\:bg-white { background-color: #fff; }
.dark\:bg-black { background-color: #000; }
}Enabled
Set enabled: false to suppress output for a utility without removing it from the $utilities map. This is useful when you want to keep the utility's definition available for reference or downstream map.get() calls, but don't want it to emit any CSS. See Using the API for the load order this example needs.
// _my-utilities.scss
@use "sass:map";
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/utilities";
$utilities: map.merge(
$utilities,
(
"float": map.merge(
map.get($utilities, "float"),
(enabled: false),
),
)
);Importance
Utilities generated by the API no longer include !important by default in v6. This is because we now use CSS layers to ensure utilities override components and modifier classes as intended. You can enable !important on a per-utility basis by setting the important option to true.
$utilities: (
"opacity": (
property: opacity,
important: true,
values: (
0: 0,
25: .25,
50: .5,
75: .75,
100: 1,
)
)
);This will generate utilities with !important:
.opacity-0 { opacity: 0 !important; }
.opacity-25 { opacity: .25 !important; }
.opacity-50 { opacity: .5 !important; }
.opacity-75 { opacity: .75 !important; }
.opacity-100 { opacity: 1 !important; }Using the API
Now that you’re familiar with how the utilities API works, learn how to add your own custom classes and modify our default utilities.
The examples below use two patterns. Pick the pattern that matches your change.
- One file—Configure
$utilitieswhen you loadbootstrap/scss/bootstrap. Use this pattern to add a utility, to replace a utility, or to remove a utility. - Two files—Put a
map.merge()call in a partial. Then load the partial beforebootstrap/scss/bootstrap. Use this pattern when your change must read the default definition. Examples are a new value, a new class prefix, or new responsive variants on a group you keep.
The one-file pattern needs one @use rule:
// my-bootstrap.scss
@use "bootstrap/scss/bootstrap" with (
$utilities: (
// Your utility groups go here
)
);Bootstrap merges your map with map.merge(). This merge is shallow. Your utility group replaces the whole default group with the same key. Supply the property and values keys in every group that emits CSS.
Sass cannot read a module and configure the same module in one file. Some changes therefore need the two-file pattern. The bootstrap/scss/config module declares $utilities. The bootstrap/scss/utilities module fills it with the default definitions. Your partial loads both modules. Then it writes the new map back to the config module.
The partial loads the config module with as *. This avoids a namespace prefix, so you can reference $utilities directly. An assignment to $utilities then writes back to the config module.
For a utility-only build, load bootstrap/scss/utilities and then bootstrap/scss/utilities/api. The API module emits the utility classes and nothing else.
// my-bootstrap-utilities.scss
@use "bootstrap/scss/utilities" with (
$utilities: (
// Your utility groups go here
)
);
@use "bootstrap/scss/utilities/api";Override utilities
Override an existing utility with the same key. Pass the new definition in the $utilities configuration when you load Bootstrap. For example, take our existing overflow utility class definition:
"overflow": (
property: overflow,
values: auto hidden visible scroll,
),
"overflow-x": (
property: overflow-x,
values: auto hidden visible scroll,
),
"overflow-y": (
property: overflow-y,
values: auto hidden visible scroll,
),
If you want to make those responsive, and adjust the values used, you can do this:
// my-bootstrap.scss
@use "bootstrap/scss/bootstrap" with (
$utilities: (
"overflow": (
property: overflow,
responsive: true,
values: visible hidden scroll auto,
),
)
);Your group replaces the default group. Keep the property key, or the build stops with an error.
Add utilities
Add a new utility with the $utilities configuration. Bootstrap merges your map on top of its defaults, so supply only the new utilities.
// my-bootstrap.scss
@use "bootstrap/scss/bootstrap" with (
$utilities: (
"cursor": (
property: cursor,
class: cursor,
responsive: true,
values: auto pointer grab,
),
)
);Modify utilities
Modify an existing utility with map.get() and map.merge(). This change reads the default definition, so it needs the two-file pattern. In the example below, we’re adding an additional value to the width utilities:
// _my-utilities.scss
@use "sass:map";
@use "bootstrap/scss/config" as *;
// Fills `$utilities` with the default definitions
@use "bootstrap/scss/utilities";
$utilities: map.merge(
$utilities,
(
"width": map.merge(
map.get($utilities, "width"),
(
values: map.merge(
map.get(map.get($utilities, "width"), "values"),
(20: 20%),
),
),
),
)
);Load your partial first. Then load Bootstrap:
// my-bootstrap.scss
@use "my-utilities";
@use "bootstrap/scss/bootstrap";Enable responsive
You can enable responsive classes for an existing set of utilities that are not currently responsive by default. This change keeps the default definition, so it needs the two-file pattern. For example, to make the border classes responsive:
// _my-utilities.scss
@use "sass:map";
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/utilities";
$utilities: map.merge(
$utilities,
(
"border": map.merge(
map.get($utilities, "border"),
(responsive: true),
),
)
);Load this partial before bootstrap/scss/bootstrap, as shown above. You can also restate the whole group with the one-file pattern. See Override utilities.
This will now generate responsive variations of .border and .border-0 for each breakpoint. Your generated CSS will look like this:
.border { ... }
.border-0 { ... }
@media (min-width: 576px) {
.sm\:border { ... }
.sm\:border-0 { ... }
}
@media (min-width: 768px) {
.md\:border { ... }
.md\:border-0 { ... }
}
@media (min-width: 1024px) {
.lg\:border { ... }
.lg\:border-0 { ... }
}
@media (min-width: 1280px) {
.xl\:border { ... }
.xl\:border-0 { ... }
}
@media (min-width: 1536px) {
.2xl\:border { ... }
.2xl\:border-0 { ... }
}Rename utilities
Missing v4 utilities, or used to another naming convention? The utilities API can be used to override the resulting class of a given utility. This change keeps the default definition, so it needs the two-file pattern. For example, to rename .ms-* utilities to oldish .ml-*:
// _my-utilities.scss
@use "sass:map";
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/utilities";
$utilities: map.merge(
$utilities,
(
"margin-start": map.merge(
map.get($utilities, "margin-start"),
(class: ml),
),
)
);Load this partial before bootstrap/scss/bootstrap, as shown above.
Remove utilities
Remove a default utility with the $utilities configuration. Set the group key to null.
// my-bootstrap.scss
@use "bootstrap/scss/bootstrap" with (
$utilities: (
"width": null,
"float": null,
)
);You can also remove utilities with the map.remove() Sass function. This function reads the default map, so it needs the two-file pattern.
// _my-utilities.scss
@use "sass:map";
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/utilities";
$utilities: map.remove($utilities, "width", "float");Load this partial before bootstrap/scss/bootstrap, as shown above.
Add, remove, modify
You can add, remove, and modify many utilities all at once with the map.merge() Sass function. Here’s how you can combine the previous examples into one larger map.
// _my-utilities.scss
@use "sass:map";
@use "bootstrap/scss/config" as *;
@use "bootstrap/scss/utilities";
$utilities: map.merge(
$utilities,
(
// Remove the `width` utility
"width": null,
// Make an existing utility responsive
"border": map.merge(
map.get($utilities, "border"),
(responsive: true),
),
// Add a new utility
"cursor": (
property: cursor,
class: cursor,
responsive: true,
values: auto pointer grab,
),
)
);Then load the partial before Bootstrap:
// my-bootstrap.scss
@use "my-utilities";
@use "bootstrap/scss/bootstrap";