Loading Components

Beautiful loading indicators and progress bars built with TailwindCSS. Perfect for async operations, page loads, and user feedback. Copy, paste, and customize for React, Vue, or HTML.

1. Classic Spinners

Traditional circular spinners with different styles and animations for loading states.

Basic Spinner

Dotted Spinner

Loading...

Thick Border

<!-- Basic Spinner -->
<div class="w-8 h-8 border-4 border-violet border-t-transparent rounded-full animate-spin"></div>

<!-- Dotted Spinner -->
<div class="w-8 h-8 border-4 border-dotted border-blue-500 border-t-transparent rounded-full animate-spin"></div>

<!-- Large Spinner with Text -->
<div class="text-center">
  <div class="w-12 h-12 border-4 border-green-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
  <p class="text-sm text-gray-600">Loading...</p>
</div>

<!-- Thick Border Spinner -->
<div class="w-10 h-10 border-8 border-orange-500 border-t-transparent rounded-full animate-spin"></div>
<template>
  <div class="flex flex-wrap justify-center items-center gap-8">
    <!-- Basic Spinner -->
    <div class="text-center">
      <div class="w-8 h-8 border-4 border-violet border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
      <p class="text-sm text-gray-600">Basic Spinner</p>
    </div>

    <!-- Dotted Spinner -->
    <div class="text-center">
      <div class="w-8 h-8 border-4 border-dotted border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
      <p class="text-sm text-gray-600">Dotted Spinner</p>
    </div>

    <!-- Large Spinner with Text -->
    <div class="text-center">
      <div class="w-12 h-12 border-4 border-green-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
      <p class="text-sm text-gray-600">{{ loadingText }}</p>
    </div>

    <!-- Thick Border Spinner -->
    <div class="text-center">
      <div class="w-10 h-10 border-8 border-orange-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
      <p class="text-sm text-gray-600">Thick Border</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const loadingText = ref('Loading...')
</script>
import React from 'react'

export default function ClassicSpinners() {
  const loadingText = 'Loading...'

  return (
    <div className="flex flex-wrap justify-center items-center gap-8">
      {/* Basic Spinner */}
      <div className="text-center">
        <div className="w-8 h-8 border-4 border-violet border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
        <p className="text-sm text-gray-600">Basic Spinner</p>
      </div>

      {/* Dotted Spinner */}
      <div className="text-center">
        <div className="w-8 h-8 border-4 border-dotted border-blue-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
        <p className="text-sm text-gray-600">Dotted Spinner</p>
      </div>

      {/* Large Spinner with Text */}
      <div className="text-center">
        <div className="w-12 h-12 border-4 border-green-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
        <p className="text-sm text-gray-600">{loadingText}</p>
      </div>

      {/* Thick Border Spinner */}
      <div className="text-center">
        <div className="w-10 h-10 border-8 border-orange-500 border-t-transparent rounded-full animate-spin mx-auto mb-2"></div>
        <p className="text-sm text-gray-600">Thick Border</p>
      </div>
    </div>
  )
}

2. Bouncing Dots

Animated bouncing dots with different patterns and colors for a modern loading experience.

Three Dots

Colorful Dots

Large Dots

<style>
.bounce {
  animation: bounce 1.4s ease-in-out infinite both;
}
.bounce:nth-child(1) { animation-delay: -0.32s; }
.bounce:nth-child(2) { animation-delay: -0.16s; }
.bounce:nth-child(3) { animation-delay: 0s; }
.bounce:nth-child(4) { animation-delay: 0.16s; }
.bounce:nth-child(5) { animation-delay: 0.32s; }

@keyframes bounce {
  0%, 80%, 100% { transform: scale(0); }
  40% { transform: scale(1.0); }
}
</style>

<!-- Three Bouncing Dots -->
<div class="flex space-x-1">
  <div class="w-3 h-3 bg-violet rounded-full bounce"></div>
  <div class="w-3 h-3 bg-violet rounded-full bounce"></div>
  <div class="w-3 h-3 bg-violet rounded-full bounce"></div>
</div>

<!-- Five Colorful Dots -->
<div class="flex space-x-1">
  <div class="w-2 h-2 bg-red-500 rounded-full bounce"></div>
  <div class="w-2 h-2 bg-yellow-500 rounded-full bounce"></div>
  <div class="w-2 h-2 bg-green-500 rounded-full bounce"></div>
  <div class="w-2 h-2 bg-blue-500 rounded-full bounce"></div>
  <div class="w-2 h-2 bg-purple-500 rounded-full bounce"></div>
</div>

<!-- Large Dots -->
<div class="flex space-x-2">
  <div class="w-4 h-4 bg-blue-500 rounded-full bounce"></div>
  <div class="w-4 h-4 bg-blue-500 rounded-full bounce"></div>
  <div class="w-4 h-4 bg-blue-500 rounded-full bounce"></div>
</div>
<template>
  <div class="flex flex-wrap justify-center items-center gap-12">
    <!-- Three Bouncing Dots -->
    <div class="text-center">
      <div class="flex space-x-1 mb-4">
        <div 
          v-for="n in 3" 
          :key="n"
          :class="['w-3 h-3 rounded-full bounce', dotColor]"
        ></div>
      </div>
      <p class="text-sm text-gray-600">Three Dots</p>
    </div>

    <!-- Five Colorful Dots -->
    <div class="text-center">
      <div class="flex space-x-1 mb-4">
        <div 
          v-for="(color, index) in colorfulDots" 
          :key="index"
          :class="['w-2 h-2 rounded-full bounce', color]"
        ></div>
      </div>
      <p class="text-sm text-gray-600">Colorful Dots</p>
    </div>

    <!-- Large Dots -->
    <div class="text-center">
      <div class="flex space-x-2 mb-4">
        <div 
          v-for="n in 3" 
          :key="n"
          class="w-4 h-4 bg-blue-500 rounded-full bounce"
        ></div>
      </div>
      <p class="text-sm text-gray-600">Large Dots</p>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const dotColor = ref('bg-violet')
const colorfulDots = ref([
  'bg-red-500',
  'bg-yellow-500',
  'bg-green-500',
  'bg-blue-500',
  'bg-purple-500'
])
</script>

<style scoped>
.bounce {
  animation: bounce 1.4s ease-in-out infinite both;
}
.bounce:nth-child(1) { animation-delay: -0.32s; }
.bounce:nth-child(2) { animation-delay: -0.16s; }
.bounce:nth-child(3) { animation-delay: 0s; }
.bounce:nth-child(4) { animation-delay: 0.16s; }
.bounce:nth-child(5) { animation-delay: 0.32s; }

@keyframes bounce {
  0%, 80%, 100% { transform: scale(0); }
  40% { transform: scale(1.0); }
}
</style>
import React from 'react'

const BouncingDots = () => {
  const dotColor = 'bg-violet'
  const colorfulDots = ['bg-red-500', 'bg-yellow-500', 'bg-green-500', 'bg-blue-500', 'bg-purple-500']

  return (
    <>
      <style jsx>{`
        .bounce {
          animation: bounce 1.4s ease-in-out infinite both;
        }
        .bounce:nth-child(1) { animation-delay: -0.32s; }
        .bounce:nth-child(2) { animation-delay: -0.16s; }
        .bounce:nth-child(3) { animation-delay: 0s; }
        .bounce:nth-child(4) { animation-delay: 0.16s; }
        .bounce:nth-child(5) { animation-delay: 0.32s; }

        @keyframes bounce {
          0%, 80%, 100% { transform: scale(0); }
          40% { transform: scale(1.0); }
        }
      `}</style>
      
      <div className="flex flex-wrap justify-center items-center gap-12">
        {/* Three Bouncing Dots */}
        <div className="text-center">
          <div className="flex space-x-1 mb-4">
            {Array.from({ length: 3 }).map((_, index) => (
              <div key={index} className={`w-3 h-3 rounded-full bounce ${dotColor}`} />
            ))}
          </div>
          <p className="text-sm text-gray-600">Three Dots</p>
        </div>

        {/* Five Colorful Dots */}
        <div className="text-center">
          <div className="flex space-x-1 mb-4">
            {colorfulDots.map((color, index) => (
              <div key={index} className={`w-2 h-2 rounded-full bounce ${color}`} />
            ))}
          </div>
          <p className="text-sm text-gray-600">Colorful Dots</p>
        </div>

        {/* Large Dots */}
        <div className="text-center">
          <div className="flex space-x-2 mb-4">
            {Array.from({ length: 3 }).map((_, index) => (
              <div key={index} className="w-4 h-4 bg-blue-500 rounded-full bounce" />
            ))}
          </div>
          <p className="text-sm text-gray-600">Large Dots</p>
        </div>
      </div>
    </>
  )
}

export default BouncingDots

3. Progress Bars & Pulse

Advanced loading indicators with progress bars, pulse animations, and skeleton loaders for sophisticated UIs.

Animated Progress Bar

65% Complete

Pulse Ring

Skeleton Loader

Indeterminate Progress

<style>
.pulse-ring {
  animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
}
@keyframes pulse-ring {
  0% { transform: scale(0.33); }
  80%, 100% { transform: scale(1.33); opacity: 0; }
}
</style>

<!-- Progress Bar -->
<div class="w-80 bg-gray-200 rounded-full h-2">
  <div class="bg-violet h-2 rounded-full animate-pulse" style="width: 65%"></div>
</div>
<p class="text-xs text-gray-500 mt-2">65% Complete</p>

<!-- Pulse Ring -->
<div class="relative inline-flex">
  <div class="w-12 h-12 bg-violet rounded-full"></div>
  <div class="absolute top-0 left-0 w-12 h-12 bg-violet rounded-full pulse-ring"></div>
</div>

<!-- Skeleton Loader -->
<div class="flex items-center space-x-4">
  <div class="w-12 h-12 bg-gray-300 rounded-full animate-pulse"></div>
  <div class="flex-1 space-y-2">
    <div class="h-4 bg-gray-300 rounded animate-pulse"></div>
    <div class="h-3 bg-gray-300 rounded w-3/4 animate-pulse"></div>
  </div>
</div>

<!-- Indeterminate Progress -->
<div class="w-80 bg-gray-200 rounded-full h-2 overflow-hidden">
  <div class="h-full bg-gradient-to-r from-violet to-blue-500 rounded-full animate-bounce" style="width: 30%; margin-left: 35%"></div>
</div>
<template>
  <div class="space-y-12">
    <!-- Progress Bar -->
    <div class="text-center">
      <p class="text-sm text-gray-600 mb-4">Animated Progress Bar</p>
      <div class="w-80 mx-auto bg-gray-200 rounded-full h-2">
        <div 
          class="bg-violet h-2 rounded-full animate-pulse transition-all duration-500" 
          :style="{ width: progress + '%' }"
        ></div>
      </div>
      <p class="text-xs text-gray-500 mt-2">{{ progress }}% Complete</p>
    </div>

    <!-- Pulse Ring -->
    <div class="text-center">
      <p class="text-sm text-gray-600 mb-4">Pulse Ring</p>
      <div class="relative inline-flex">
        <div :class="['w-12 h-12 rounded-full', ringColor]"></div>
        <div :class="['absolute top-0 left-0 w-12 h-12 rounded-full pulse-ring', ringColor]"></div>
      </div>
    </div>

    <!-- Skeleton Loader -->
    <div class="text-center">
      <p class="text-sm text-gray-600 mb-4">Skeleton Loader</p>
      <div class="max-w-md mx-auto space-y-3">
        <div class="flex items-center space-x-4">
          <div class="w-12 h-12 bg-gray-300 rounded-full animate-pulse"></div>
          <div class="flex-1 space-y-2">
            <div class="h-4 bg-gray-300 rounded animate-pulse"></div>
            <div class="h-3 bg-gray-300 rounded w-3/4 animate-pulse"></div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'

const progress = ref(65)
const ringColor = ref('bg-violet')

// Simulate progress update
onMounted(() => {
  const interval = setInterval(() => {
    progress.value = (progress.value + 1) % 101
  }, 100)
  
  // Clean up on unmount
  return () => clearInterval(interval)
})
</script>

<style scoped>
.pulse-ring {
  animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
}
@keyframes pulse-ring {
  0% { transform: scale(0.33); }
  80%, 100% { transform: scale(1.33); opacity: 0; }
}
</style>
import React, { useState, useEffect } from 'react'

const ProgressAndPulse = () => {
  const [progress, setProgress] = useState(65)
  const ringColor = 'bg-violet'

  // Simulate progress update
  useEffect(() => {
    const interval = setInterval(() => {
      setProgress(prev => (prev + 1) % 101)
    }, 100)

    return () => clearInterval(interval)
  }, [])

  return (
    <>
      <style jsx>{`
        .pulse-ring {
          animation: pulse-ring 1.25s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
        }
        @keyframes pulse-ring {
          0% { transform: scale(0.33); }
          80%, 100% { transform: scale(1.33); opacity: 0; }
        }
      `}</style>

      <div className="space-y-12">
        {/* Progress Bar */}
        <div className="text-center">
          <p className="text-sm text-gray-600 mb-4">Animated Progress Bar</p>
          <div className="w-80 mx-auto bg-gray-200 rounded-full h-2">
            <div 
              className="bg-violet h-2 rounded-full animate-pulse transition-all duration-500" 
              
            />
          </div>
          <p className="text-xs text-gray-500 mt-2">{progress}% Complete</p>
        </div>

        {/* Pulse Ring */}
        <div className="text-center">
          <p className="text-sm text-gray-600 mb-4">Pulse Ring</p>
          <div className="relative inline-flex">
            <div className={`w-12 h-12 rounded-full ${ringColor}`} />
            <div className={`absolute top-0 left-0 w-12 h-12 rounded-full pulse-ring ${ringColor}`} />
          </div>
        </div>

        {/* Skeleton Loader */}
        <div className="text-center">
          <p className="text-sm text-gray-600 mb-4">Skeleton Loader</p>
          <div className="max-w-md mx-auto space-y-3">
            <div className="flex items-center space-x-4">
              <div className="w-12 h-12 bg-gray-300 rounded-full animate-pulse" />
              <div className="flex-1 space-y-2">
                <div className="h-4 bg-gray-300 rounded animate-pulse" />
                <div className="h-3 bg-gray-300 rounded w-3/4 animate-pulse" />
              </div>
            </div>
          </div>
        </div>

        {/* Indeterminate Progress */}
        <div className="text-center">
          <p className="text-sm text-gray-600 mb-4">Indeterminate Progress</p>
          <div className="w-80 mx-auto bg-gray-200 rounded-full h-2 overflow-hidden">
            <div className="h-full bg-gradient-to-r from-violet to-blue-500 rounded-full animate-bounce" 
            
            />
          </div>
        </div>
      </div>
    </>
  )
}

export default ProgressAndPulse

We use cookies to improve your experience and analytics. You can accept all cookies or reject non-essential ones.

Learn More