Default

Standard spinner at default size.

<svg class="spinner" role="status" aria-label="Loading" viewBox="0 0 24 24"
     fill="none" stroke="currentColor" stroke-width="2"
     stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>

Sizes

Small, default, medium, and large.

<svg class="spinner" data-size="sm">...</svg>
<svg class="spinner">...</svg>
<svg class="spinner" data-size="md">...</svg>
<svg class="spinner" data-size="lg">...</svg>

In Button

Spinner inside a loading button.

<button class="btn" data-variant="default" disabled>
  <svg class="spinner" data-size="sm" aria-hidden="true">...</svg>
  Loading...
</button>

CSS view file

Styles for the spinner component. Uses design tokens for colors, spacing, and radius.

@layer components {
  .spinner {
    width: 1rem;
    height: 1rem;
    animation: spinner-rotate 1s linear infinite;
    color: var(--muted-foreground);
    flex-shrink: 0;

    &[data-size="sm"] {
      width: 0.875rem;
      height: 0.875rem;
    }

    &[data-size="md"] {
      width: 1.25rem;
      height: 1.25rem;
    }

    &[data-size="lg"] {
      width: 1.5rem;
      height: 1.5rem;
    }
  }

  @keyframes spinner-rotate {
    to { transform: rotate(360deg); }
  }
}