Barber pole

No dependencies
Code format
React + Tailwind
const css = `
  /* One stripe period measured straight up the tube: 14.142px along a 45deg gradient. */
  @keyframes loader-barber-climb { to { transform: translateY(-20px); } }
  .loader-barber { position: relative; display: flex; flex-direction: column; align-items: center; width: 40px; height: 104px; }
  .loader-barber__finial { width: 10px; height: 10px; border-radius: 50%; background: light-dark(#5f626a, #a7abb2); box-shadow: inset -2px -2px 0 light-dark(rgba(0, 0, 0, 0.05), rgba(0, 0, 0, 0.18)); }
  .loader-barber__cap { width: 32px; height: 10px; margin-top: -1px; border-radius: 16px 16px 3px 3px; background: light-dark(#6d7179, #7d8087); box-shadow: inset 0 -2px 0 light-dark(rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.2)); }
  .loader-barber__collar { width: 28px; height: 4px; border-radius: 1px; background: light-dark(#cbced3, #393c41); }
  .loader-barber__tube { position: relative; width: 24px; height: 62px; overflow: hidden; background: light-dark(#ebedf0, #232529); }
  .loader-barber__stripes {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: calc(100% + 20px);
    background: repeating-linear-gradient(135deg, light-dark(#42454c, #e5e6e9) 0 4.95px, light-dark(#ebedf0, #232529) 4.95px 7.07px, light-dark(#6d7179, #7d8087) 7.07px 12.02px, light-dark(#ebedf0, #232529) 12.02px 14.142px);
    animation: loader-barber-climb 0.9s linear infinite;
  }
  /* The round of the glass: darker at both edges, a highlight down the left. */
  .loader-barber__tube::after { content: ''; position: absolute; inset: 0; box-shadow: inset 6px 0 6px -3px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.45)), inset -6px 0 6px -3px light-dark(rgba(0, 0, 0, 0.14), rgba(0, 0, 0, 0.45)); }
  .loader-barber__tube::before { content: ''; position: absolute; z-index: 1; top: 0; bottom: 0; left: 5px; width: 3px; border-radius: 2px; background: light-dark(#fbfcfd, #f1f2f3); opacity: 0.4; }
  .loader-barber__base { width: 32px; height: 9px; border-radius: 3px 3px 14px 14px; background: light-dark(#6d7179, #7d8087); box-shadow: inset 0 2px 0 light-dark(rgba(0, 0, 0, 0.06), rgba(0, 0, 0, 0.2)); }
  .loader-barber__foot { width: 14px; height: 6px; border-radius: 0 0 3px 3px; background: light-dark(#cbced3, #393c41); }
  @media (prefers-reduced-motion: reduce) {
    .loader-barber__stripes { animation: none; }
  }
`;

export function BarberLoader() {
  return (
    <>
      <style>
        {css}
      </style>
      <div className="loader-barber" role="status" aria-label="Loading">
        <span className="loader-barber__finial" aria-hidden="true" />
        <span className="loader-barber__cap" aria-hidden="true" />
        <span className="loader-barber__collar" aria-hidden="true" />
        <span className="loader-barber__tube" aria-hidden="true">
          <span className="loader-barber__stripes" />
        </span>
        <span className="loader-barber__collar" aria-hidden="true" />
        <span className="loader-barber__base" aria-hidden="true" />
        <span className="loader-barber__foot" aria-hidden="true" />
      </div>
    </>
  );
}

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

Install with shadcn

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

About this component

A barber pole: the striped glass tube turns forever, its stripes climbing endlessly between the domed caps.

Dependencies
None
Difficulty
Beginner
Triggers
continuous, loop, gradient
Techniques
gradient, keyframes, 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 stripes are still.

More loaders

See all
Ferris wheel
Geneva drive
Hamster
Jellyfish