Interactive Demo

Drag the slider to see progress bar animation.

Loading... 50%

Linear Progress Bar

Show determinate progress for tasks with known completion percentage.

Uploading... 25%
Processing... 60%
Almost done! 90%
<div class="progress-bar">
  <div class="progress-fill" style="width: 60%"></div>
</div>

Indeterminate Progress

For operations with unknown duration.

Loading...
<div class="progress-bar">
  <div class="progress-fill progress-indeterminate"></div>
</div>

Size Variants

Different sizes for various contexts.

Slim
Default
Large
<div class="progress-bar progress-bar-sm">...</div>
<div class="progress-bar">...</div>
<div class="progress-bar progress-bar-lg">...</div>

Persona Colors

Use persona accent colors for branded progress indicators.

Ferni
Maya
Jordan
<div class="progress-fill progress-ferni" style="width: 80%"></div>
<div class="progress-fill progress-maya" style="width: 65%"></div>
<div class="progress-fill progress-jordan" style="width: 45%"></div>

Circular Spinner

Classic loading spinner for async operations.

Small
Default
Large
<div class="spinner spinner-sm"></div>
<div class="spinner"></div>
<div class="spinner spinner-lg"></div>

Persona Spinners

Spinners with persona accent colors.

Ferni
Maya
Alex
Jordan
Peter
Nayan
<div class="spinner spinner-ferni"></div>
<div class="spinner spinner-maya"></div>

Pulse Loader

Gentle pulsing animation for background loading.

<div class="pulse-loader">
  <div class="pulse-dot"></div>
  <div class="pulse-dot"></div>
  <div class="pulse-dot"></div>
</div>

Button Loading States

Inline loading indicators for buttons.

<button class="btn btn-primary btn-loading">
  <div class="spinner spinner-sm spinner-white"></div>
  <span>Saving...</span>
</button>

Skeleton Loading

Placeholder content while data loads.

<div class="skeleton-card">
  <div class="skeleton-avatar"></div>
  <div class="skeleton-content">
    <div class="skeleton-line skeleton-line-title"></div>
    <div class="skeleton-line"></div>
  </div>
</div>

Step Progress

Multi-step process indicator.

Account
2
Profile
3
Preferences
4
Complete
<div class="step-progress">
  <div class="step completed">
    <div class="step-indicator">✓</div>
    <span class="step-label">Account</span>
  </div>
  <div class="step-connector completed"></div>
  <div class="step active">
    <div class="step-indicator">2</div>
    <span class="step-label">Profile</span>
  </div>
  ...
</div>

CSS Implementation

/* Linear Progress Bar */
.progress-bar {
  width: 100%;
  height: 8px;
  background: var(--bg-tertiary);
  border-radius: var(--radius-full);
  overflow: hidden;
}

.progress-bar-sm { height: 4px; }
.progress-bar-lg { height: 12px; }

.progress-fill {
  height: 100%;
  background: var(--accent-primary);
  border-radius: var(--radius-full);
  transition: width var(--duration-normal) var(--ease-ease-out);
}

/* Indeterminate Animation */
.progress-indeterminate {
  width: 30% !important;
  animation: indeterminate 1.5s ease-in-out infinite;
}

@keyframes indeterminate {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(400%); }
}

/* Persona Colors */
.progress-ferni { background: var(--persona-ferni); }
.progress-maya { background: var(--persona-maya); }
.progress-jordan { background: var(--persona-jordan); }

/* Spinner */
.spinner {
  width: 24px;
  height: 24px;
  border: 3px solid var(--border-subtle);
  border-top-color: var(--accent-primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

.spinner-sm { width: 16px; height: 16px; border-width: 2px; }
.spinner-lg { width: 40px; height: 40px; border-width: 4px; }

.spinner-white { border-color: rgba(255,255,255,0.3); border-top-color: white; }
.spinner-ferni { border-top-color: var(--persona-ferni); }
.spinner-maya { border-top-color: var(--persona-maya); }

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

/* Pulse Loader */
.pulse-loader {
  display: flex;
  gap: var(--space-2);
}

.pulse-dot {
  width: 10px;
  height: 10px;
  background: var(--accent-primary);
  border-radius: 50%;
  animation: pulse 1.4s ease-in-out infinite;
}

.pulse-dot:nth-child(2) { animation-delay: 0.2s; }
.pulse-dot:nth-child(3) { animation-delay: 0.4s; }

@keyframes pulse {
  0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
  40% { opacity: 1; transform: scale(1); }
}

/* Skeleton */
.skeleton-line {
  height: 12px;
  background: linear-gradient(
    90deg,
    var(--bg-tertiary) 25%,
    var(--bg-secondary) 50%,
    var(--bg-tertiary) 75%
  );
  background-size: 200% 100%;
  animation: shimmer 1.5s infinite;
  border-radius: var(--radius-sm);
}

@keyframes shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}

/* Step Progress */
.step-progress {
  display: flex;
  align-items: center;
}

.step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
}

.step-indicator {
  width: 32px;
  height: 32px;
  border: 2px solid var(--border-medium);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: var(--font-weight-semibold);
  font-size: var(--text-sm);
  color: var(--text-muted);
  background: var(--bg-primary);
}

.step.active .step-indicator {
  border-color: var(--accent-primary);
  color: var(--accent-primary);
}

.step.completed .step-indicator {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: white;
}

.step-connector {
  flex: 1;
  height: 2px;
  background: var(--border-subtle);
  margin: 0 var(--space-2);
}

.step-connector.completed {
  background: var(--accent-primary);
}

Accessibility

  • ARIA roles: Use role="progressbar" with aria-valuenow, aria-valuemin, aria-valuemax
  • Live regions: Announce progress updates with aria-live="polite"
  • Reduced motion: Respect prefers-reduced-motion - use opacity changes instead of animation
  • Focus management: Don't trap focus during loading states
  • Text alternatives: Provide status text for screen readers, not just visual indicators

Usage Guidelines

✓ Do

  • Use determinate progress when completion is known
  • Show estimated time for long operations
  • Allow cancellation when possible
  • Use skeleton loaders for content-heavy pages

✗ Don't

  • Use progress bars for instant operations
  • Show multiple spinners simultaneously
  • Block the entire UI during loading
  • Use animation-heavy loaders on low-end devices