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