Category · Interactive Difficulty Level · Intermediate Published on · January 15, 2024

Animated Button Components

A comprehensive collection of modern animated buttons with various styles, effects, and interactive features for enhanced user experience

#buttons #animation #hover #effects #components #ui

Responsive Design

Yes

Dark Mode Support

No

lines

78

Browser Compatibility

No

Live Preview

Interact with the component without leaving the page.

700px

Animated Button Components

A comprehensive collection of modern animated buttons featuring various styles, hover effects, loading states, and interactive animations to enhance user experience and interface engagement.

Features

  • Multiple Button Styles: Primary, secondary, outline, ghost, and gradient buttons
  • Smooth Animations: CSS-based transitions with customizable timing
  • Hover Effects: Scale, glow, ripple, and morphing animations
  • Loading States: Spinner, progress, and pulse loading indicators
  • Icon Integration: Support for icons with smooth transitions
  • Responsive Design: Adapts to all screen sizes and touch devices
  • Accessibility Support: ARIA attributes and keyboard navigation
  • Modern Design: Clean aesthetics with subtle shadow effects

Demo

<div class="button-demo-container">
  <!-- Basic Button Styles -->
  <div class="button-section">
    <h3>Basic Button Styles</h3>
    <div class="button-grid">
      <button class="btn btn-primary">
        <span class="btn-text">Primary Button</span>
      </button>
      
      <button class="btn btn-secondary">
        <span class="btn-text">Secondary Button</span>
      </button>
      
      <button class="btn btn-outline">
        <span class="btn-text">Outline Button</span>
      </button>
      
      <button class="btn btn-ghost">
        <span class="btn-text">Ghost Button</span>
      </button>
      
      <button class="btn btn-gradient">
        <span class="btn-text">Gradient Button</span>
      </button>
      
      <button class="btn btn-danger">
        <span class="btn-text">Danger Button</span>
      </button>
    </div>
  </div>

  <!-- Animated Effects -->
  <div class="button-section">
    <h3>Animated Effects</h3>
    <div class="button-grid">
      <button class="btn btn-primary btn-scale">
        <span class="btn-text">Scale Effect</span>
      </button>
      
      <button class="btn btn-primary btn-glow">
        <span class="btn-text">Glow Effect</span>
      </button>
      
      <button class="btn btn-primary btn-ripple">
        <span class="btn-text">Ripple Effect</span>
        <span class="btn-ripple"></span>
      </button>
      
      <button class="btn btn-primary btn-slide">
        <span class="btn-text">Slide Effect</span>
        <span class="btn-slide-bg"></span>
      </button>
      
      <button class="btn btn-primary btn-bounce">
        <span class="btn-text">Bounce Effect</span>
      </button>
      
      <button class="btn btn-primary btn-rotate">
        <span class="btn-text">Rotate Effect</span>
      </button>
    </div>
  </div>

  <!-- Icon Buttons -->
  <div class="button-section">
    <h3>Icon Buttons</h3>
    <div class="button-grid">
      <button class="btn btn-primary btn-icon">
        <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
        </svg>
        <span class="btn-text">Add Item</span>
      </button>
      
      <button class="btn btn-secondary btn-icon">
        <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
        </svg>
        <span class="btn-text">Edit</span>
      </button>
      
      <button class="btn btn-danger btn-icon">
        <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
        </svg>
        <span class="btn-text">Delete</span>
      </button>
      
      <button class="btn btn-outline btn-icon-only" aria-label="Settings">
        <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/>
        </svg>
      </button>
      
      <button class="btn btn-ghost btn-icon-only" aria-label="Search">
        <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
        </svg>
      </button>
      
      <button class="btn btn-primary btn-icon-only" aria-label="Favorite">
        <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
          <path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
        </svg>
      </button>
    </div>
  </div>

  <!-- Loading States -->
  <div class="button-section">
    <h3>Loading States</h3>
    <div class="button-grid">
      <button class="btn btn-primary btn-loading">
        <span class="btn-spinner"></span>
        <span class="btn-text">Loading...</span>
      </button>
      
      <button class="btn btn-secondary btn-loading-dots">
        <span class="btn-text">Processing</span>
        <span class="btn-dots">
          <span class="dot"></span>
          <span class="dot"></span>
          <span class="dot"></span>
        </span>
      </button>
      
      <button class="btn btn-outline btn-loading-progress">
        <span class="btn-text">Uploading</span>
        <span class="btn-progress">
          <span class="btn-progress-bar"></span>
        </span>
      </button>
      
      <button class="btn btn-gradient btn-pulse">
        <span class="btn-text">Syncing</span>
      </button>
    </div>
  </div>

  <!-- Size Variations -->
  <div class="button-section">
    <h3>Size Variations</h3>
    <div class="button-grid">
      <button class="btn btn-primary btn-small">
        <span class="btn-text">Small</span>
      </button>
      
      <button class="btn btn-primary btn-medium">
        <span class="btn-text">Medium</span>
      </button>
      
      <button class="btn btn-primary btn-large">
        <span class="btn-text">Large</span>
      </button>
      
      <button class="btn btn-primary btn-extra-large">
        <span class="btn-text">Extra Large</span>
      </button>
    </div>
  </div>

  <!-- Special Effects -->
  <div class="button-section">
    <h3>Special Effects</h3>
    <div class="button-grid">
      <button class="btn btn-neon">
        <span class="btn-text">Neon Effect</span>
      </button>
      
      <button class="btn btn-glass">
        <span class="btn-text">Glass Effect</span>
      </button>
      
      <button class="btn btn-3d">
        <span class="btn-text">3D Effect</span>
      </button>
      
      <button class="btn btn-liquid">
        <span class="btn-text">Liquid Effect</span>
        <span class="btn-liquid-bg"></span>
      </button>
      
      <button class="btn btn-magnetic">
        <span class="btn-text">Magnetic Effect</span>
      </button>
      
      <button class="btn btn-particle">
        <span class="btn-text">Particle Effect</span>
        <canvas class="btn-particle-canvas"></canvas>
      </button>
    </div>
  </div>

  <!-- Toggle Buttons -->
  <div class="button-section">
    <h3>Toggle Buttons</h3>
    <div class="button-grid">
      <button class="btn btn-toggle" data-toggle="false">
        <span class="btn-text">Toggle Me</span>
      </button>
      
      <button class="btn btn-switch" data-switch="false">
        <span class="btn-switch-track">
          <span class="btn-switch-thumb"></span>
        </span>
        <span class="btn-text">Switch</span>
      </button>
      
      <button class="btn btn-checkbox" data-checked="false">
        <span class="btn-checkbox-mark">
          <svg viewBox="0 0 24 24" fill="currentColor">
            <path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z"/>
          </svg>
        </span>
        <span class="btn-text">Checkbox</span>
      </button>
    </div>
  </div>
</div>
.button-demo-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 2rem;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  min-height: 100vh;
}

.button-section {
  margin-bottom: 4rem;
  padding: 2rem;
  background: white;
  border-radius: 16px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.button-section h3 {
  margin: 0 0 2rem 0;
  font-size: 1.5rem;
  font-weight: 700;
  color: #1a1a1a;
  text-align: center;
  position: relative;
}

.button-section h3::after {
  content: '';
  position: absolute;
  bottom: -0.5rem;
  left: 50%;
  transform: translateX(-50%);
  width: 60px;
  height: 3px;
  background: linear-gradient(90deg, #3b82f6, #8b5cf6);
  border-radius: 2px;
}

.button-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1.5rem;
  align-items: center;
  justify-items: center;
}

/* Base Button Styles */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border: none;
  border-radius: 8px;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.3s ease;
  overflow: hidden;
  user-select: none;
  outline: none;
  min-width: 120px;
  background: transparent;
}

.btn:focus {
  box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}

.btn:disabled {
  opacity: 0.6;
  cursor: not-allowed;
  transform: none !important;
}

.btn-text {
  position: relative;
  z-index: 2;
  transition: all 0.3s ease;
}

.btn-icon-svg {
  width: 20px;
  height: 20px;
  transition: all 0.3s ease;
}

/* Button Variants */
.btn-primary {
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  color: white;
  box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3);
}

.btn-primary:hover {
  background: linear-gradient(135deg, #2563eb, #1e40af);
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4);
}

.btn-secondary {
  background: linear-gradient(135deg, #6b7280, #4b5563);
  color: white;
  box-shadow: 0 4px 15px rgba(107, 114, 128, 0.3);
}

.btn-secondary:hover {
  background: linear-gradient(135deg, #4b5563, #374151);
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(107, 114, 128, 0.4);
}

.btn-outline {
  background: transparent;
  color: #3b82f6;
  border: 2px solid #3b82f6;
}

.btn-outline:hover {
  background: #3b82f6;
  color: white;
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(59, 130, 246, 0.3);
}

.btn-ghost {
  background: transparent;
  color: #6b7280;
  border: 1px solid transparent;
}

.btn-ghost:hover {
  background: #f3f4f6;
  color: #374151;
  border-color: #e5e7eb;
  transform: translateY(-1px);
}

.btn-gradient {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}

.btn-gradient:hover {
  background: linear-gradient(135deg, #5a67d8 0%, #6b46c1 100%);
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
}

.btn-danger {
  background: linear-gradient(135deg, #ef4444, #dc2626);
  color: white;
  box-shadow: 0 4px 15px rgba(239, 68, 68, 0.3);
}

.btn-danger:hover {
  background: linear-gradient(135deg, #dc2626, #b91c1c);
  transform: translateY(-2px);
  box-shadow: 0 8px 25px rgba(239, 68, 68, 0.4);
}

/* Animated Effects */
.btn-scale:hover {
  transform: scale(1.05);
}

.btn-glow {
  position: relative;
}

.btn-glow::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border-radius: 8px;
  background: linear-gradient(135deg, #3b82f6, #1d4ed8);
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: -1;
  filter: blur(10px);
}

.btn-glow:hover::before {
  opacity: 0.7;
}

.btn-ripple {
  overflow: hidden;
}

.btn-ripple .btn-ripple {
  position: absolute;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.6);
  transform: scale(0);
  animation: ripple 0.6s linear;
  pointer-events: none;
}

@keyframes ripple {
  to {
    transform: scale(4);
    opacity: 0;
  }
}

.btn-slide {
  overflow: hidden;
}

.btn-slide-bg {
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: rgba(255, 255, 255, 0.1);
  transition: left 0.3s ease;
  z-index: 1;
}

.btn-slide:hover .btn-slide-bg {
  left: 0;
}

.btn-bounce:hover {
  animation: bounce 0.6s ease;
}

@keyframes bounce {
  0%, 20%, 60%, 100% {
    transform: translateY(0);
  }
  40% {
    transform: translateY(-10px);
  }
  80% {
    transform: translateY(-5px);
  }
}

.btn-rotate:hover {
  transform: rotateY(180deg);
}

/* Icon Button Styles */
.btn-icon {
  gap: 0.75rem;
}

.btn-icon-only {
  width: 48px;
  height: 48px;
  padding: 0;
  border-radius: 50%;
  min-width: auto;
}

.btn-icon:hover .btn-icon-svg {
  transform: scale(1.1);
}

/* Loading States */
.btn-loading {
  pointer-events: none;
}

.btn-spinner {
  width: 20px;
  height: 20px;
  border: 2px solid transparent;
  border-top: 2px solid currentColor;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

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

.btn-loading-dots .btn-dots {
  display: flex;
  gap: 4px;
  margin-left: 8px;
}

.btn-dots .dot {
  width: 6px;
  height: 6px;
  background: currentColor;
  border-radius: 50%;
  animation: dotPulse 1.4s ease-in-out infinite both;
}

.btn-dots .dot:nth-child(1) { animation-delay: -0.32s; }
.btn-dots .dot:nth-child(2) { animation-delay: -0.16s; }

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

.btn-loading-progress {
  position: relative;
  overflow: hidden;
}

.btn-progress {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: rgba(255, 255, 255, 0.2);
}

.btn-progress-bar {
  display: block;
  width: 0;
  height: 100%;
  background: currentColor;
  animation: progressBar 2s ease-in-out infinite;
}

@keyframes progressBar {
  0% { width: 0; }
  50% { width: 70%; }
  100% { width: 100%; }
}

.btn-pulse {
  animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    opacity: 1;
  }
  50% {
    opacity: 0.7;
  }
}

/* Size Variations */
.btn-small {
  padding: 0.5rem 1rem;
  font-size: 0.875rem;
  min-width: 80px;
}

.btn-medium {
  padding: 0.75rem 1.5rem;
  font-size: 1rem;
  min-width: 120px;
}

.btn-large {
  padding: 1rem 2rem;
  font-size: 1.125rem;
  min-width: 160px;
}

.btn-extra-large {
  padding: 1.25rem 2.5rem;
  font-size: 1.25rem;
  min-width: 200px;
}

/* Special Effects */
.btn-neon {
  background: transparent;
  color: #00ffff;
  border: 2px solid #00ffff;
  text-shadow: 0 0 10px #00ffff;
  box-shadow: 0 0 20px rgba(0, 255, 255, 0.3);
}

.btn-neon:hover {
  background: #00ffff;
  color: #000;
  text-shadow: none;
  box-shadow: 0 0 30px rgba(0, 255, 255, 0.6);
}

.btn-glass {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: #333;
}

.btn-glass:hover {
  background: rgba(255, 255, 255, 0.2);
  transform: translateY(-2px);
}

.btn-3d {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  box-shadow: 0 8px 0 #5a67d8, 0 12px 20px rgba(0, 0, 0, 0.3);
  transform: translateY(0);
}

.btn-3d:hover {
  transform: translateY(4px);
  box-shadow: 0 4px 0 #5a67d8, 0 8px 15px rgba(0, 0, 0, 0.3);
}

.btn-3d:active {
  transform: translateY(8px);
  box-shadow: 0 0 0 #5a67d8, 0 4px 10px rgba(0, 0, 0, 0.3);
}

.btn-liquid {
  background: #3b82f6;
  color: white;
  overflow: hidden;
}

.btn-liquid-bg {
  position: absolute;
  top: 100%;
  left: 0;
  width: 100%;
  height: 100%;
  background: #1d4ed8;
  transition: top 0.3s ease;
  z-index: 1;
}

.btn-liquid:hover .btn-liquid-bg {
  top: 0;
}

.btn-magnetic {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  transition: all 0.1s ease;
}

.btn-particle {
  background: #1a1a1a;
  color: white;
  position: relative;
  overflow: hidden;
}

.btn-particle-canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 1;
}

/* Toggle Buttons */
.btn-toggle {
  background: #e5e7eb;
  color: #6b7280;
  transition: all 0.3s ease;
}

.btn-toggle.active {
  background: #3b82f6;
  color: white;
}

.btn-switch {
  background: transparent;
  color: #6b7280;
  padding: 0.5rem;
  gap: 1rem;
}

.btn-switch-track {
  width: 48px;
  height: 24px;
  background: #e5e7eb;
  border-radius: 12px;
  position: relative;
  transition: background 0.3s ease;
}

.btn-switch-thumb {
  width: 20px;
  height: 20px;
  background: white;
  border-radius: 50%;
  position: absolute;
  top: 2px;
  left: 2px;
  transition: transform 0.3s ease;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

.btn-switch.active .btn-switch-track {
  background: #3b82f6;
}

.btn-switch.active .btn-switch-thumb {
  transform: translateX(24px);
}

.btn-checkbox {
  background: transparent;
  color: #6b7280;
  border: 2px solid #d1d5db;
  gap: 1rem;
}

.btn-checkbox-mark {
  width: 20px;
  height: 20px;
  border: 2px solid #d1d5db;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}

.btn-checkbox-mark svg {
  width: 14px;
  height: 14px;
  opacity: 0;
  transform: scale(0);
  transition: all 0.3s ease;
}

.btn-checkbox.active {
  border-color: #3b82f6;
  color: #3b82f6;
}

.btn-checkbox.active .btn-checkbox-mark {
  background: #3b82f6;
  border-color: #3b82f6;
}

.btn-checkbox.active .btn-checkbox-mark svg {
  opacity: 1;
  transform: scale(1);
  color: white;
}

/* Dark Theme */
.dark .button-section {
  background: #1f2937;
  border-color: #374151;
}

.dark .button-section h3 {
  color: #f9fafb;
}

.dark .btn-ghost {
  color: #d1d5db;
}

.dark .btn-ghost:hover {
  background: #374151;
  color: #f3f4f6;
  border-color: #4b5563;
}

.dark .btn-glass {
  background: rgba(0, 0, 0, 0.2);
  color: #e5e7eb;
  border-color: rgba(255, 255, 255, 0.1);
}

.dark .btn-toggle {
  background: #374151;
  color: #d1d5db;
}

.dark .btn-switch-track {
  background: #374151;
}

.dark .btn-checkbox {
  border-color: #4b5563;
  color: #d1d5db;
}

.dark .btn-checkbox-mark {
  border-color: #4b5563;
}

/* Responsive Design */
@media (max-width: 768px) {
  .button-demo-container {
    padding: 1rem;
  }
  
  .button-section {
    padding: 1.5rem;
    margin-bottom: 2rem;
  }
  
  .button-grid {
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 1rem;
  }
  
  .btn {
    min-width: 100px;
    padding: 0.625rem 1.25rem;
    font-size: 0.875rem;
  }
  
  .btn-large,
  .btn-extra-large {
    padding: 0.75rem 1.5rem;
    font-size: 1rem;
    min-width: 120px;
  }
}

@media (max-width: 480px) {
  .button-grid {
    grid-template-columns: 1fr;
  }
  
  .btn {
    width: 100%;
    max-width: 280px;
  }
}

/* Reduced Motion */
@media (prefers-reduced-motion: reduce) {
  .btn,
  .btn-spinner,
  .btn-dots .dot,
  .btn-progress-bar,
  .btn-switch-thumb,
  .btn-checkbox-mark svg {
    transition: none;
    animation: none;
  }
}

/* Focus Styles */
.btn:focus-visible {
  outline: 2px solid #3b82f6;
  outline-offset: 2px;
}

/* High Contrast Mode */
@media (prefers-contrast: high) {
  .btn {
    border: 2px solid;
  }
  
  .btn-primary {
    background: #0000ff;
    border-color: #0000ff;
  }
  
  .btn-secondary {
    background: #666666;
    border-color: #666666;
  }
  
  .btn-danger {
    background: #ff0000;
    border-color: #ff0000;
  }
}
class AnimatedButtonComponents {
  constructor() {
    this.buttons = new Map();
    this.rippleButtons = [];
    this.particleButtons = [];
    this.magneticButtons = [];
    
    this.init();
  }

  init() {
    this.setupEventListeners();
    this.initializeRippleEffect();
    this.initializeParticleEffect();
    this.initializeMagneticEffect();
    this.initializeToggleButtons();
    this.setupAccessibility();
  }

  setupEventListeners() {
    document.addEventListener('click', (e) => {
      const button = e.target.closest('.btn');
      if (!button) return;

      // Handle toggle buttons
      if (button.classList.contains('btn-toggle')) {
        this.handleToggle(button);
      }
      
      if (button.classList.contains('btn-switch')) {
        this.handleSwitch(button);
      }
      
      if (button.classList.contains('btn-checkbox')) {
        this.handleCheckbox(button);
      }
      
      // Handle ripple effect
      if (button.classList.contains('btn-ripple')) {
        this.createRipple(e, button);
      }
      
      // Trigger custom events
      this.dispatchButtonEvent('buttonClick', {
        button,
        type: this.getButtonType(button)
      });
    });

    // Handle keyboard navigation
    document.addEventListener('keydown', (e) => {
      if (e.key === 'Enter' || e.key === ' ') {
        const button = e.target.closest('.btn');
        if (button) {
          e.preventDefault();
          button.click();
        }
      }
    });
  }

  initializeRippleEffect() {
    const rippleButtons = document.querySelectorAll('.btn-ripple');
    rippleButtons.forEach(button => {
      this.rippleButtons.push(button);
    });
  }

  createRipple(event, button) {
    const ripple = document.createElement('span');
    const rect = button.getBoundingClientRect();
    const size = Math.max(rect.width, rect.height);
    const x = event.clientX - rect.left - size / 2;
    const y = event.clientY - rect.top - size / 2;
    
    ripple.className = 'btn-ripple';
    ripple.style.width = ripple.style.height = size + 'px';
    ripple.style.left = x + 'px';
    ripple.style.top = y + 'px';
    
    // Remove existing ripples
    const existingRipples = button.querySelectorAll('.btn-ripple');
    existingRipples.forEach(r => r.remove());
    
    button.appendChild(ripple);
    
    setTimeout(() => {
      ripple.remove();
    }, 600);
  }

  initializeParticleEffect() {
    const particleButtons = document.querySelectorAll('.btn-particle');
    particleButtons.forEach(button => {
      const canvas = button.querySelector('.btn-particle-canvas');
      if (canvas) {
        this.setupParticleCanvas(button, canvas);
        this.particleButtons.push({ button, canvas });
      }
    });
  }

  setupParticleCanvas(button, canvas) {
    const ctx = canvas.getContext('2d');
    const particles = [];
    
    const resizeCanvas = () => {
      const rect = button.getBoundingClientRect();
      canvas.width = rect.width;
      canvas.height = rect.height;
    };
    
    resizeCanvas();
    window.addEventListener('resize', resizeCanvas);
    
    button.addEventListener('mouseenter', () => {
      this.startParticleAnimation(ctx, canvas, particles);
    });
    
    button.addEventListener('mouseleave', () => {
      particles.length = 0;
    });
  }

  startParticleAnimation(ctx, canvas, particles) {
    const createParticle = () => {
      return {
        x: Math.random() * canvas.width,
        y: Math.random() * canvas.height,
        vx: (Math.random() - 0.5) * 2,
        vy: (Math.random() - 0.5) * 2,
        life: 1,
        decay: Math.random() * 0.02 + 0.01
      };
    };
    
    const animate = () => {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      
      // Add new particles
      if (particles.length < 20 && Math.random() < 0.3) {
        particles.push(createParticle());
      }
      
      // Update and draw particles
      for (let i = particles.length - 1; i >= 0; i--) {
        const particle = particles[i];
        
        particle.x += particle.vx;
        particle.y += particle.vy;
        particle.life -= particle.decay;
        
        if (particle.life <= 0) {
          particles.splice(i, 1);
          continue;
        }
        
        ctx.save();
        ctx.globalAlpha = particle.life;
        ctx.fillStyle = '#ffffff';
        ctx.beginPath();
        ctx.arc(particle.x, particle.y, 2, 0, Math.PI * 2);
        ctx.fill();
        ctx.restore();
      }
      
      if (particles.length > 0) {
        requestAnimationFrame(animate);
      }
    };
    
    animate();
  }

  initializeMagneticEffect() {
    const magneticButtons = document.querySelectorAll('.btn-magnetic');
    magneticButtons.forEach(button => {
      this.setupMagneticEffect(button);
      this.magneticButtons.push(button);
    });
  }

  setupMagneticEffect(button) {
    button.addEventListener('mousemove', (e) => {
      const rect = button.getBoundingClientRect();
      const x = e.clientX - rect.left - rect.width / 2;
      const y = e.clientY - rect.top - rect.height / 2;
      
      const distance = Math.sqrt(x * x + y * y);
      const maxDistance = Math.max(rect.width, rect.height) / 2;
      
      if (distance < maxDistance) {
        const strength = (maxDistance - distance) / maxDistance;
        const moveX = x * strength * 0.3;
        const moveY = y * strength * 0.3;
        
        button.style.transform = `translate(${moveX}px, ${moveY}px)`;
      }
    });
    
    button.addEventListener('mouseleave', () => {
      button.style.transform = 'translate(0, 0)';
    });
  }

  initializeToggleButtons() {
    const toggleButtons = document.querySelectorAll('.btn-toggle, .btn-switch, .btn-checkbox');
    toggleButtons.forEach(button => {
      const initialState = button.dataset.toggle === 'true' || 
                          button.dataset.switch === 'true' || 
                          button.dataset.checked === 'true';
      
      if (initialState) {
        button.classList.add('active');
      }
      
      this.buttons.set(button, {
        type: this.getButtonType(button),
        state: initialState
      });
    });
  }

  handleToggle(button) {
    const buttonData = this.buttons.get(button);
    const newState = !buttonData.state;
    
    buttonData.state = newState;
    button.dataset.toggle = newState.toString();
    
    if (newState) {
      button.classList.add('active');
    } else {
      button.classList.remove('active');
    }
    
    this.dispatchButtonEvent('buttonToggle', {
      button,
      state: newState
    });
  }

  handleSwitch(button) {
    const buttonData = this.buttons.get(button);
    const newState = !buttonData.state;
    
    buttonData.state = newState;
    button.dataset.switch = newState.toString();
    
    if (newState) {
      button.classList.add('active');
    } else {
      button.classList.remove('active');
    }
    
    this.dispatchButtonEvent('buttonSwitch', {
      button,
      state: newState
    });
  }

  handleCheckbox(button) {
    const buttonData = this.buttons.get(button);
    const newState = !buttonData.state;
    
    buttonData.state = newState;
    button.dataset.checked = newState.toString();
    
    if (newState) {
      button.classList.add('active');
    } else {
      button.classList.remove('active');
    }
    
    this.dispatchButtonEvent('buttonCheck', {
      button,
      checked: newState
    });
  }

  getButtonType(button) {
    if (button.classList.contains('btn-toggle')) return 'toggle';
    if (button.classList.contains('btn-switch')) return 'switch';
    if (button.classList.contains('btn-checkbox')) return 'checkbox';
    if (button.classList.contains('btn-primary')) return 'primary';
    if (button.classList.contains('btn-secondary')) return 'secondary';
    if (button.classList.contains('btn-outline')) return 'outline';
    if (button.classList.contains('btn-ghost')) return 'ghost';
    if (button.classList.contains('btn-gradient')) return 'gradient';
    if (button.classList.contains('btn-danger')) return 'danger';
    return 'default';
  }

  setupAccessibility() {
    // Add ARIA attributes
    const buttons = document.querySelectorAll('.btn');
    buttons.forEach(button => {
      if (!button.getAttribute('role')) {
        button.setAttribute('role', 'button');
      }
      
      if (!button.hasAttribute('tabindex')) {
        button.setAttribute('tabindex', '0');
      }
      
      // Add aria-pressed for toggle buttons
      if (button.classList.contains('btn-toggle') || 
          button.classList.contains('btn-switch') || 
          button.classList.contains('btn-checkbox')) {
        const isPressed = button.classList.contains('active');
        button.setAttribute('aria-pressed', isPressed.toString());
      }
    });
  }

  dispatchButtonEvent(eventName, detail) {
    const event = new CustomEvent(eventName, {
      detail,
      bubbles: true,
      cancelable: true
    });
    document.dispatchEvent(event);
  }

  // Public API
  setButtonState(button, state) {
    if (typeof button === 'string') {
      button = document.querySelector(button);
    }
    
    if (!button) return;
    
    const buttonData = this.buttons.get(button);
    if (!buttonData) return;
    
    buttonData.state = state;
    
    if (button.classList.contains('btn-toggle')) {
      button.dataset.toggle = state.toString();
    } else if (button.classList.contains('btn-switch')) {
      button.dataset.switch = state.toString();
    } else if (button.classList.contains('btn-checkbox')) {
      button.dataset.checked = state.toString();
    }
    
    if (state) {
      button.classList.add('active');
    } else {
      button.classList.remove('active');
    }
    
    button.setAttribute('aria-pressed', state.toString());
  }

  getButtonState(button) {
    if (typeof button === 'string') {
      button = document.querySelector(button);
    }
    
    const buttonData = this.buttons.get(button);
    return buttonData ? buttonData.state : null;
  }

  setLoadingState(button, loading = true) {
    if (typeof button === 'string') {
      button = document.querySelector(button);
    }
    
    if (!button) return;
    
    if (loading) {
      button.classList.add('btn-loading');
      button.disabled = true;
      button.setAttribute('aria-busy', 'true');
    } else {
      button.classList.remove('btn-loading');
      button.disabled = false;
      button.setAttribute('aria-busy', 'false');
    }
  }

  destroy() {
    // Clean up event listeners and animations
    this.rippleButtons = [];
    this.particleButtons = [];
    this.magneticButtons = [];
    this.buttons.clear();
  }
}

// Auto-initialize
let animatedButtonComponents;
document.addEventListener('DOMContentLoaded', () => {
  animatedButtonComponents = new AnimatedButtonComponents();
});

// Export for module usage
if (typeof module !== 'undefined' && module.exports) {
  module.exports = AnimatedButtonComponents;
}

// Global API
window.AnimatedButtonComponents = AnimatedButtonComponents;

Usage Examples

Basic Button Implementation

<!-- Basic animated button -->
<button class="btn btn-primary btn-scale">
  <span class="btn-text">Click Me</span>
</button>

<!-- Button with icon -->
<button class="btn btn-secondary btn-icon">
  <svg class="btn-icon-svg" viewBox="0 0 24 24" fill="currentColor">
    <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
  </svg>
  <span class="btn-text">Add Item</span>
</button>

<!-- Loading button -->
<button class="btn btn-primary btn-loading">
  <span class="btn-spinner"></span>
  <span class="btn-text">Loading...</span>
</button>

JavaScript Integration

// Initialize the component
const buttonComponent = new AnimatedButtonComponents();

// Set button loading state
buttonComponent.setLoadingState('#submit-btn', true);

// Handle button events
document.addEventListener('buttonClick', (e) => {
  console.log('Button clicked:', e.detail.button);
  console.log('Button type:', e.detail.type);
});

// Handle toggle events
document.addEventListener('buttonToggle', (e) => {
  console.log('Toggle state:', e.detail.state);
});

// Set toggle button state programmatically
buttonComponent.setButtonState('#my-toggle', true);

// Get button state
const isToggled = buttonComponent.getButtonState('#my-toggle');
console.log('Button is toggled:', isToggled);

Custom Button Creation

// Create a custom animated button
function createCustomButton(text, type = 'primary', effects = []) {
  const button = document.createElement('button');
  button.className = `btn btn-${type} ${effects.map(e => `btn-${e}`).join(' ')}`;
  
  const textSpan = document.createElement('span');
  textSpan.className = 'btn-text';
  textSpan.textContent = text;
  button.appendChild(textSpan);
  
  // Add ripple effect if specified
  if (effects.includes('ripple')) {
    const rippleSpan = document.createElement('span');
    rippleSpan.className = 'btn-ripple';
    button.appendChild(rippleSpan);
  }
  
  return button;
}

// Usage
const customButton = createCustomButton('Custom Button', 'gradient', ['scale', 'glow']);
document.body.appendChild(customButton);

API Reference

Methods

setButtonState(button, state)

Sets the state of a toggle, switch, or checkbox button.

Parameters:

  • button (Element|string): Button element or CSS selector
  • state (boolean): New state value
buttonComponent.setButtonState('#my-toggle', true);

getButtonState(button)

Gets the current state of a toggle, switch, or checkbox button.

Parameters:

  • button (Element|string): Button element or CSS selector

Returns: boolean|null

const state = buttonComponent.getButtonState('#my-toggle');

setLoadingState(button, loading)

Sets the loading state of a button.

Parameters:

  • button (Element|string): Button element or CSS selector
  • loading (boolean): Loading state (default: true)
buttonComponent.setLoadingState('#submit-btn', true);

destroy()

Cleans up all event listeners and animations.

buttonComponent.destroy();

Events

buttonClick

Fired when any button is clicked.

Event Detail:

  • button (Element): The clicked button element
  • type (string): Button type (primary, secondary, etc.)
document.addEventListener('buttonClick', (e) => {
  console.log('Clicked button:', e.detail.button);
});

buttonToggle

Fired when a toggle button state changes.

Event Detail:

  • button (Element): The toggle button element
  • state (boolean): New toggle state
document.addEventListener('buttonToggle', (e) => {
  console.log('Toggle state:', e.detail.state);
});

buttonSwitch

Fired when a switch button state changes.

Event Detail:

  • button (Element): The switch button element
  • state (boolean): New switch state
document.addEventListener('buttonSwitch', (e) => {
  console.log('Switch state:', e.detail.state);
});

buttonCheck

Fired when a checkbox button state changes.

Event Detail:

  • button (Element): The checkbox button element
  • checked (boolean): New checked state
document.addEventListener('buttonCheck', (e) => {
  console.log('Checkbox checked:', e.detail.checked);
});

CSS Classes

Button Types

  • .btn-primary - Primary button style
  • .btn-secondary - Secondary button style
  • .btn-outline - Outline button style
  • .btn-ghost - Ghost button style
  • .btn-gradient - Gradient button style
  • .btn-danger - Danger button style

Animation Effects

  • .btn-scale - Scale animation on hover
  • .btn-glow - Glow effect on hover
  • .btn-ripple - Ripple effect on click
  • .btn-slide - Slide background effect
  • .btn-bounce - Bounce animation on hover
  • .btn-rotate - Rotation effect on hover

Special Effects

  • .btn-neon - Neon glow effect
  • .btn-glass - Glass morphism effect
  • .btn-3d - 3D button effect
  • .btn-liquid - Liquid fill effect
  • .btn-magnetic - Magnetic mouse tracking
  • .btn-particle - Particle animation effect

Sizes

  • .btn-small - Small button size
  • .btn-medium - Medium button size (default)
  • .btn-large - Large button size
  • .btn-extra-large - Extra large button size

States

  • .btn-loading - Loading state
  • .btn-loading-dots - Loading with dots animation
  • .btn-loading-progress - Loading with progress bar
  • .btn-pulse - Pulsing animation

Customization

CSS Variables

Customize the button appearance using CSS variables:

:root {
  --btn-primary-bg: linear-gradient(135deg, #3b82f6, #1d4ed8);
  --btn-primary-hover-bg: linear-gradient(135deg, #2563eb, #1e40af);
  --btn-primary-shadow: 0 4px 15px rgba(59, 130, 246, 0.3);
  --btn-primary-hover-shadow: 0 8px 25px rgba(59, 130, 246, 0.4);
  
  --btn-border-radius: 8px;
  --btn-padding: 0.75rem 1.5rem;
  --btn-font-size: 1rem;
  --btn-font-weight: 600;
  
  --btn-transition: all 0.3s ease;
  --btn-hover-transform: translateY(-2px);
  
  --btn-focus-shadow: 0 0 0 3px rgba(59, 130, 246, 0.3);
}

Custom Animations

Add your own button animations:

.btn-custom-effect {
  position: relative;
  overflow: hidden;
}

.btn-custom-effect::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
  transition: left 0.5s ease;
}

.btn-custom-effect:hover::before {
  left: 100%;
}

Theme Integration

/* Light theme */
.theme-light {
  --btn-text-color: #1f2937;
  --btn-bg-color: #ffffff;
  --btn-border-color: #e5e7eb;
}

/* Dark theme */
.theme-dark {
  --btn-text-color: #f9fafb;
  --btn-bg-color: #1f2937;
  --btn-border-color: #374151;
}

Accessibility

ARIA Support

The component automatically adds appropriate ARIA attributes:

  • role="button" for all buttons
  • aria-pressed for toggle buttons
  • aria-busy for loading states
  • tabindex="0" for keyboard navigation

Keyboard Navigation

  • Enter/Space: Activate button
  • Tab: Navigate between buttons
  • Escape: Cancel loading state (if implemented)

Screen Reader Support

<!-- Provide descriptive labels -->
<button class="btn btn-primary" aria-label="Submit form">
  <span class="btn-text">Submit</span>
</button>

<!-- Use aria-describedby for additional context -->
<button class="btn btn-danger" aria-describedby="delete-warning">
  <span class="btn-text">Delete</span>
</button>
<div id="delete-warning" class="sr-only">
  This action cannot be undone
</div>

Reduced Motion

The component respects prefers-reduced-motion settings:

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
    animation: none;
  }
}

Browser Support

  • Chrome: 60+
  • Firefox: 55+
  • Safari: 12+
  • Edge: 79+
  • iOS Safari: 12+
  • Android Chrome: 60+

Fallbacks

For older browsers, the component gracefully degrades:

/* Fallback for browsers without CSS Grid */
.button-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

/* Fallback for browsers without backdrop-filter */
.btn-glass {
  background: rgba(255, 255, 255, 0.9);
}

@supports (backdrop-filter: blur(10px)) {
  .btn-glass {
    background: rgba(255, 255, 255, 0.1);
    backdrop-filter: blur(10px);
  }
}

Performance Considerations

Optimization Tips

  1. Use CSS transforms instead of changing layout properties
  2. Limit particle effects to avoid performance issues
  3. Debounce rapid interactions for better UX
  4. Use will-change for frequently animated elements
.btn-animated {
  will-change: transform;
}

.btn-animated:hover {
  transform: translateY(-2px) scale(1.02);
}

Memory Management

// Clean up when component is no longer needed
window.addEventListener('beforeunload', () => {
  if (animatedButtonComponents) {
    animatedButtonComponents.destroy();
  }
});

Integration Examples

React Integration

import React, { useEffect, useRef } from 'react';

const AnimatedButton = ({ children, type = 'primary', effects = [], onClick }) => {
  const buttonRef = useRef(null);
  
  useEffect(() => {
    // Initialize button component if needed
    if (window.AnimatedButtonComponents && buttonRef.current) {
      // Component will auto-initialize
    }
  }, []);
  
  const handleClick = (e) => {
    if (onClick) {
      onClick(e);
    }
  };
  
  const className = `btn btn-${type} ${effects.map(e => `btn-${e}`).join(' ')}`;
  
  return (
    <button ref={buttonRef} className={className} onClick={handleClick}>
      <span className="btn-text">{children}</span>
    </button>
  );
};

// Usage
<AnimatedButton type="primary" effects={['scale', 'glow']} onClick={handleSubmit}>
  Submit Form
</AnimatedButton>

Vue Integration

<template>
  <button 
    ref="buttonRef"
    :class="buttonClasses" 
    @click="handleClick"
  >
    <span class="btn-text">{{ children }}</span>
  </button>
</template>

<script>
export default {
  name: 'AnimatedButton',
  props: {
    type: {
      type: String,
      default: 'primary'
    },
    effects: {
      type: Array,
      default: () => []
    },
    children: {
      type: String,
      required: true
    }
  },
  computed: {
    buttonClasses() {
      return [
        'btn',
        `btn-${this.type}`,
        ...this.effects.map(effect => `btn-${effect}`)
      ].join(' ');
    }
  },
  mounted() {
    // Component will auto-initialize
  },
  methods: {
    handleClick(e) {
      this.$emit('click', e);
    }
  }
};
</script>

Angular Integration

import { Component, Input, Output, EventEmitter, ElementRef, AfterViewInit } from '@angular/core';

@Component({
  selector: 'app-animated-button',
  template: `
    <button [class]="buttonClasses" (click)="handleClick($event)">
      <span class="btn-text"><ng-content></ng-content></span>
    </button>
  `
})
export class AnimatedButtonComponent implements AfterViewInit {
  @Input() type: string = 'primary';
  @Input() effects: string[] = [];
  @Output() buttonClick = new EventEmitter<Event>();
  
  constructor(private elementRef: ElementRef) {}
  
  ngAfterViewInit() {
    // Component will auto-initialize
  }
  
  get buttonClasses(): string {
    return [
      'btn',
      `btn-${this.type}`,
      ...this.effects.map(effect => `btn-${effect}`)
    ].join(' ');
  }
  
  handleClick(event: Event) {
    this.buttonClick.emit(event);
  }
}

This comprehensive animated button component collection provides a wide variety of modern, accessible, and performant button styles with smooth animations and interactive effects. The component is designed to be easily customizable and integrates seamlessly with popular frameworks while maintaining excellent browser support and accessibility standards.

HTML

17

lines

CSS

61

lines


                <div class="button-demo-container">
  <button class="btn btn-primary">
    <span class="btn-text">Primary Button</span>
  </button>
  
  <button class="btn btn-secondary">
    <span class="btn-text">Secondary Button</span>
  </button>
  
  <button class="btn btn-outline">
    <span class="btn-text">Outline Button</span>
  </button>
  
  <button class="btn btn-gradient">
    <span class="btn-text">Gradient Button</span>
  </button>
</div>

              
17lines
442characters
HTMLLanguage

Related Code Snippets

Explore template packs

Need larger building blocks? Browse responsive landing pages and component bundles.

Open HTML Template Library →