Spinner
A loading spinner to indicate an ongoing process.
Default
Basic spinning circle indicator.
html
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-6 vt-w-6 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
Sizes
Small (16px), medium (24px), large (32px), and extra-large (48px) spinners.
html
sm
md
lg
xl
<div class="vt-flex vt-flex-col vt-items-center vt-gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-4 vt-w-4 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-xs vt-text-foreground-muted">sm</span>
</div>
<div class="vt-flex vt-flex-col vt-items-center vt-gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-6 vt-w-6 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-xs vt-text-foreground-muted">md</span>
</div>
<div class="vt-flex vt-flex-col vt-items-center vt-gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-8 vt-w-8 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-xs vt-text-foreground-muted">lg</span>
</div>
<div class="vt-flex vt-flex-col vt-items-center vt-gap-2">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-12 vt-w-12 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-xs vt-text-foreground-muted">xl</span>
</div>
With Label
Spinner accompanied by a text label.
html
Loading...
Please wait while we process your request...
Loading content...
<div class="vt-flex vt-items-center vt-gap-3">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-5 vt-w-5 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-sm vt-text-foreground-muted">Loading...</span>
</div>
<div class="vt-flex vt-items-center vt-gap-3">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-5 vt-w-5 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-sm vt-text-foreground-muted">Please wait while we process your request...</span>
</div>
<div class="vt-flex vt-flex-col vt-items-center vt-gap-3 vt-py-4">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-8 vt-w-8 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<span class="vt-text-sm vt-text-foreground-muted">Loading content...</span>
</div>
Button with Spinner
Buttons showing a loading state with an embedded spinner.
html
<button disabled="" class="vt-btn vt-btn-primary vt-gap-2 vt-opacity-70 vt-cursor-not-allowed">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-4 vt-w-4">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
Loading...
</button>
<button disabled="" class="vt-btn vt-btn-secondary vt-gap-2 vt-opacity-70 vt-cursor-not-allowed">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-4 vt-w-4">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
Saving...
</button>
<button disabled="" class="vt-btn vt-btn-bordered vt-gap-2 vt-opacity-70 vt-cursor-not-allowed">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-4 vt-w-4">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
Uploading...
</button>
<button disabled="" class="vt-btn vt-btn-danger vt-gap-2 vt-opacity-70 vt-cursor-not-allowed">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-4 vt-w-4">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
Deleting...
</button>
<button class="vt-btn vt-btn-primary">
Submit
</button>
Full Page Overlay
A spinner overlay covering the full page. Click the button to preview.
html
Loading, please wait...
(Click anywhere to dismiss)
<button class="vt-btn vt-btn-primary" onclick="document.getElementById('overlay-spinner').classList.remove('vt-hidden')">
Show Overlay Spinner
</button>
<div id="overlay-spinner" class="vt-hidden vt-fixed vt-inset-0 vt-z-[100] vt-bg-surface-card/80 vt-flex vt-flex-col vt-items-center vt-justify-center vt-gap-4" onclick="this.classList.add('vt-hidden')">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" class="lucide lucide-loader-circle vt-animate-spin vt-h-12 vt-w-12 vt-text-info-fill">
<path d="M21 12a9 9 0 1 1-6.219-8.56"></path>
</svg>
<p class="vt-text-sm vt-text-foreground-muted">Loading, please wait...</p>
<p class="vt-text-xs vt-text-foreground-muted vt-mt-2">(Click anywhere to dismiss)</p>
</div>
Guidelines
Signal an indeterminate wait when the duration is unknown; for measurable progress use a progress bar.
Loading...
Do
Don't
API Reference
All CSS classes available for the Spinner component.
| Class | Type | Description |
|---|---|---|
vt-animate-spin |
Animation | Applies continuous rotation animation to the spinner |
vt-h-4 vt-w-4 |
Size | Small spinner (16px) |
vt-h-6 vt-w-6 |
Size | Medium spinner (24px, default) |
vt-h-8 vt-w-8 |
Size | Large spinner (32px) |
vt-h-12 vt-w-12 |
Size | Extra-large spinner (48px) |
vt-text-info-fill |
Color | Primary spinner color |
vt-text-foreground-muted |
Color | Muted label text color |
vt-opacity-70 |
State | Reduced opacity for loading button state |
vt-cursor-not-allowed |
State | Not-allowed cursor for disabled loading buttons |
vt-fixed vt-inset-0 |
Layout | Full-page overlay positioning |
vt-bg-surface-card/80 |
Overlay | Semi-transparent surface background for overlay |
Accessibility
Keyboard and screen reader support.
| Feature | Details |
|---|---|
| Role | Use role="status" on the spinner container for screen reader announcement |
| Label | Add aria-label="Loading" or include sr-only "Loading..." text |
| Hidden | Hide spinner from screen readers if a separate loading announcement exists |
| Motion | Respect prefers-reduced-motion by reducing or pausing animation |