Skip to main content Skip to docs navigation

Indicate the loading state of a component or page with Chassis CSS spinners, built entirely with HTML, CSS, and no JavaScript.

About

Chassis CSS “spinners” can be used to show the loading state in your projects. They’re built only with HTML and CSS, meaning you don’t need any JavaScript to create them. You will, however, need some custom JavaScript to toggle their visibility. Their appearance, alignment, and sizing can be easily customized with our amazing utility classes.

For accessibility purposes, each loader here includes role="status" and a nested <span class="visually-hidden">Loading...</span>. We didn't include them in some examples here to keep focus on utilities.

Border spinner

Use the border spinners for a lightweight loading indicator.

Loading...
html
<div class="spinner-border" role="status">
  <span class="visually-hidden">Loading...</span>
</div>

Growing spinner

If you don’t fancy a border spinner, switch to the grow spinner. While it doesn’t technically spin, it does repeatedly grow!

Loading...
html
<div class="spinner-grow" role="status">
  <span class="visually-hidden">Loading...</span>
</div>

Default spinner

You can set default spinner in options and use .spinner class only.

Loading...
html
<div class="spinner" role="status">
  <span class="visually-hidden">Loading...</span>
</div>

Colors

Spinners use --cx-spinner-color variable for their color, which is set to --cx-icon-color by default and can be changed in options. Use .spinner-* classes to pain them any context color.

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
html
<div class="spinner spinner-default" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-alternate" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-primary" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-secondary" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-neutral" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-danger" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-success" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-warning" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-info" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-black" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-white" role="status">
  <span class="visually-hidden">Loading...</span>
</div>

Sizes

Spinners have a default size setting in options, still their size can be changed in different ways.

Icon Sizes

Spinners use icon sizes for their sizing, use .spinner-* class to apply a size.

html
<span class="spinner spinner-2xsmall"></span>
<span class="spinner spinner-xsmall"></span>
<span class="spinner spinner-small"></span>
<span class="spinner spinner-medium"></span>
<span class="spinner spinner-large"></span>
<span class="spinner spinner-xlarge"></span>
<span class="spinner spinner-2xlarge"></span>
<span class="spinner spinner-3xlarge"></span>
<span class="spinner spinner-4xlarge"></span>

CSS Variables

You can use custom CSS or inline styles to change the dimensions as needed.

html
<div style="--cx-spinner-size: 3rem;">
  <span class="spinner-grow"></span>
  <span class="spinner-grow" style="--cx-spinner-border-radius: 0;"></span>
  <span class="spinner-border" style="--cx-spinner-animation-speed: 2s"></span>
  <span class="spinner-border" style="--cx-spinner-border-width: .25rem;"></span>
</div>

Adaptive

Use the .spinner-adaptive class to make a spinner adapt to the font size of its parent element. This is useful for making spinners that are the same size as text.

Heading 1

Heading 1

Heading 1

html
<h1>
<span class="spinner spinner-adaptive"></span>
Heading 1
</h1>
<h2>
<span class="spinner spinner-adaptive"></span>
Heading 1
</h2>
<h3>
<span class="spinner spinner-adaptive"></span>
Heading 1
</h3>

Opacity

Using CSS variables for spinner utilities allows for real-time color changes without compilation and dynamic alpha transparency changes.

How it works

Consider our .spinner-* classes.

.spinner {
  --cx-color: var(--cx-spinner-color, var(--cx-icon-color));
}
.spinner-primary {
  --cx-spinner-color: var(--cx-primary);
}
.spinner-opacity-50 {
  --cx-spinner-opacity: var(--cx-opacity-50);
}

We use the --cx-primary CSS variable directly with CSS relative color syntax, and attach a second CSS variable, --cx-spinner-opacity, for the alpha transparency (with a default value 1). The oklch(from ...) expression derives the color from the variable and applies the opacity channel. Then, the opacity class overrides the default opacity by setting --cx-spinner-opacity on the element.

Example

To change that opacity, override --cx-spinner-opacity via custom styles or inline styles, or choose from any of the .spinner-opacity-* utilities:

Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
html
<span class="spinner"></span>
<span class="spinner spinner-primary" style="--cx-spinner-opacity: .6;"></span>

<span class="vr mx-medium"></span>

<div class="spinner spinner-primary spinner-opacity-100" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-primary spinner-opacity-75" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-primary spinner-opacity-50" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-primary spinner-opacity-25" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-primary spinner-opacity-10" role="status">
  <span class="visually-hidden">Loading...</span>
</div>
<div class="spinner spinner-primary spinner-opacity-0" role="status">
  <span class="visually-hidden">Loading...</span>
</div>

Context Opacity

You can directly apply a context opacity utility to match icon contexts:

html
<span class="spinner-border"></span>
<span class="spinner-border spinner-primary spinner-opacity-subtle"></span>
<span class="spinner-border spinner-primary spinner-opacity-slight"></span>

<span class="vr mx-medium"></span>

<span class="spinner-grow"></span>
<span class="spinner-grow spinner-primary spinner-opacity-subtle"></span>
<span class="spinner-grow spinner-primary spinner-opacity-slight"></span>

Buttons

Use spinners within buttons to indicate an action is currently processing or taking place. You may also swap the text out of the spinner element and utilize button text as needed.

Spinners match to icon size and color automatically when placed inside a .button.

html
<button class="button default" type="button">
  <span class="spinner-border"></span>
</button>
<button class="button default" type="button" disabled>
  <span class="spinner-border"></span>
  Loading...
</button>
<button class="button primary large" type="button">
  <span class="spinner-border"></span>
</button>
<button class="button primary large" type="button" disabled>
  <span class="spinner-border"></span>
</button>
<button class="button secondary small" type="button">
  <span class="spinner-grow"></span>
</button>
<button class="button secondary small" type="button" disabled>
  <span class="spinner-grow"></span>
  Loading...
</button>

Positioning

Spinners in Chassis CSS are built with rems and display: inline-flex. This means they can easily be resized, recolored, and quickly aligned.

Margin

Use margin utilities like .m-xlarge for easy spacing.

html
<span class="spinner-border m-xlarge"></span>

Flex

Use flexbox utilities, float utilities, or text alignment utilities to place spinners exactly where you need them in any situation.

Loading...
html
<div class="d-flex justify-content-center">
  <div class="spinner-border" role="status">
    <span class="visually-hidden">Loading...</span>
  </div>
</div>
Loading...
html
<div class="d-flex align-items-center">
  <strong role="status">Loading...</strong>
  <div class="spinner-border ms-auto" aria-hidden="true"></div>
</div>

Floats

Loading...
html
<div class="clearfix">
  <div class="spinner-border float-end" role="status">
    <span class="visually-hidden">Loading...</span>
  </div>
</div>

Text align

Loading...
html
<div class="text-center">
  <div class="spinner-border" role="status">
    <span class="visually-hidden">Loading...</span>
  </div>
</div>

CSS

This component can be customized using CSS variables, allowing for styles to be modified dynamically on the page. These CSS variables are part of Chassis CSS's design token system, giving design teams control over component appearance. See the design tokens page for more details.

Custom properties

These CSS variables control the component's appearance and can be modified dynamically on the page. Components use cascading variables, allowing seamless variations in size, color, and style without redundant style declarations through component inheritance and the context class system.

Sass variables

These Sass variables are also exposed as CSS custom properties using the --cx- prefix. A Sass variable $variable-name becomes available as --cx-variable-name in CSS, allowing for styles to be modified dynamically on the page. See the context components page for more details.

// Sass only variable to set spinner style for `.spinner` class.
$default-spinner:           spinner-border; // or spinner-grow
// These variables are also reserved as CSS variables.
$spinner-color:             var(--#{$prefix}icon-color);
$spinner-size:              1.6rem;
$spinner-vertical-align:    -.125em;
$spinner-border-width:      #{calc(var(--#{$prefix}size) / 6)};
$spinner-animation-speed:   .75s;
// See scss/maps/_index.scss for $spinner-sizes and $spinner-opacities variables.

Keyframes

Used for creating the CSS animations for our spinners. Included in scss/_spinners.scss.

@keyframes spinner-border {
  to { transform: rotate(360deg) #{"/* rtl:ignore */"}; }
}
@keyframes spinner-grow {
  0% {
    transform: scale(0);
  }
  50% {
    opacity: 1;
    transform: none;
  }
}