Spirit level

No dependencies
Code format
React + Tailwind
const css = `
  /* Tips one way, then the other, then comes level and holds. */
  @keyframes loader-level-tilt {
    0%, 4% { transform: rotate(0deg); }
    14%, 30% { transform: rotate(-7deg); }
    44%, 60% { transform: rotate(6deg); }
    72% { transform: rotate(-1deg); }
    78%, 100% { transform: rotate(0deg); }
  }
  /* The bubble runs to the high end a beat behind the tilt, with a little overshoot. */
  @keyframes loader-level-bubble {
    0%, 8% { transform: translateX(0); }
    22% { transform: translateX(13px); animation-timing-function: ease-out; }
    25%, 36% { transform: translateX(11.5px); }
    50% { transform: translateX(-13px); animation-timing-function: ease-out; }
    53%, 64% { transform: translateX(-11.5px); }
    80% { transform: translateX(1.5px); }
    86%, 100% { transform: translateX(0); }
  }
  @keyframes loader-level-mark { 0%, 82% { stroke: light-dark(#5f626a, #a7abb2); } 86%, 97% { stroke: light-dark(#373a40, #f1f2f3); } 100% { stroke: light-dark(#5f626a, #a7abb2); } }
  .loader-level { position: relative; width: 144px; height: 86px; }
  .loader-level svg { width: 100%; height: 100%; overflow: visible; }
  .loader-level__bar { transform-origin: 60px 46px; animation: loader-level-tilt 3.4s ease-in-out infinite; }
  .loader-level__body { fill: light-dark(#cbced3, #393c41); stroke: light-dark(#6d7179, #7d8087); stroke-width: 1; }
  .loader-level__cap { fill: light-dark(#6d7179, #7d8087); }
  .loader-level__vial { fill: light-dark(#cbced3, #232529); stroke: light-dark(#5f626a, #a7abb2); stroke-width: 0.8; }
  .loader-level__bubble { fill: light-dark(#fbfcfd, #e5e6e9); animation: loader-level-bubble 3.4s cubic-bezier(0.3, 1.25, 0.5, 1) infinite; }
  .loader-level__mark { stroke: light-dark(#5f626a, #a7abb2); stroke-width: 1.2; animation: loader-level-mark 3.4s linear infinite; }
  .loader-level__hole { fill: light-dark(#ebedf0, #232529); stroke: light-dark(#6d7179, #7d8087); stroke-width: 1; }
  .loader-level__fulcrum { fill: light-dark(#cbced3, #393c41); }
  .loader-level__ground { stroke: light-dark(#6d7179, #7d8087); stroke-width: 2.5; stroke-linecap: round; }
  @media (prefers-reduced-motion: reduce) {
    .loader-level__bar, .loader-level__bubble, .loader-level__mark { animation: none; }
  }
`;

export function LevelLoader() {
  return (
    <>
      <style>
        {css}
      </style>
      <div className="loader-level" role="status" aria-label="Loading">
        <svg viewBox="0 0 120 72" aria-hidden="true">
          <path className="loader-level__fulcrum" d="M60 46L51 62H69Z" />
          <path className="loader-level__ground" d="M34 62H86" />
          <g className="loader-level__bar">
            <rect className="loader-level__body" x="8" y="33" width="104" height="13" rx="3" />
            <rect className="loader-level__cap" x="8" y="33" width="9" height="13" rx="2.5" />
            <rect className="loader-level__cap" x="103" y="33" width="9" height="13" rx="2.5" />
            <circle className="loader-level__hole" cx="27" cy="39.5" r="3" />
            <circle className="loader-level__hole" cx="93" cy="39.5" r="3" />
            <rect className="loader-level__vial" x="41" y="35.5" width="38" height="8" rx="4" />
            <ellipse className="loader-level__bubble" cx="60" cy="39.5" rx="5" ry="2.6" />
            <path className="loader-level__mark" d="M54 35.5V43.5M66 35.5V43.5" />
          </g>
        </svg>
      </div>
    </>
  );
}

Free to use in any project, commercial included. MIT-0, no attribution required. Licence

Install with shadcn

npx shadcn@latest add @movin/loader-level
Source on GitHub

About this component

A spirit level rocking on a fulcrum: the bubble runs to the high end each time it tips, then it comes level and the bubble settles between the marks.

Dependencies
None
Difficulty
Beginner
Triggers
continuous, loop, spring
Techniques
keyframes, svg, transform only
Reduced motion
Respected
Theme
Light and dark (follows your page's color-scheme)

The root has role="status" and aria-label="Loading"; everything inside is decorative. Under prefers-reduced-motion the level sits flat.

More loaders

See all
Locomotive
Pancake
Popcorn
Receipt