Back

Creating Animated Icon Toggle Buttons

Learn how to build beautiful, animated toggle buttons with icons for liking, bookmarking, and more.

HTML

Let's create a set of animated icon toggle buttons for common actions like liking, bookmarking, starring, and enabling notifications. These buttons provide visual feedback through icon changes and animations. Here's the HTML structure:

        <div class="toggle-buttons-container">
          <!-- Like Toggle Button -->
          <div class="toggle-btn-wrapper">
            <button class="icon-toggle-btn" id="like-button" aria-label="Like" aria-pressed="false">
              <svg class="icon icon-default" 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">
                <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z"></path>
              </svg>
              <svg class="icon icon-active" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z"></path>
              </svg>
              <span class="toggle-label">Like</span>
            </button>
          </div>
          
          <!-- Additional toggle buttons follow the same pattern -->
        </div>
      
Our HTML structure includes these key features: - Each toggle button is wrapped in a container for proper spacing - We use two SVG icons for each button: an outline version for the default state and a filled version for the active state - We include proper accessibility attributes (`aria-label` and `aria-pressed`) - Each button has a descriptive text label under the icon - We use unique IDs for each button to allow specific styling and behavior

JavaScript

Now, let's implement the JavaScript to handle toggle functionality:

        document.addEventListener('DOMContentLoaded', () => {
          // Select all toggle buttons
          const toggleButtons = document.querySelectorAll('.icon-toggle-btn');
          
          // Function to toggle the state of a button
          function toggleButtonState(button) {
            const isPressed = button.getAttribute('aria-pressed') === 'true';
            const newState = !isPressed;
            
            // Update aria-pressed state
            button.setAttribute('aria-pressed', newState);
            
            // Add or remove active class for styling
            if (newState) {
              button.classList.add('active');
            } else {
              button.classList.remove('active');
            }
            
            // Get button ID to determine which icon is being toggled
            const buttonId = button.id;
            
            // You could trigger different actions based on the button id
            switch (buttonId) {
              case 'like-button':
                console.log(`User ${newState ? 'liked' : 'unliked'} the item`);
                break;
              case 'bookmark-button':
                console.log(`User ${newState ? 'saved' : 'removed'} the bookmark`);
                break;
              // Additional cases for other buttons
            }
            
            // Create and play animation
            if (newState) {
              button.classList.add('animate');
              // Remove animation class after it completes
              setTimeout(() => {
                button.classList.remove('animate');
              }, 700); // Match this to your CSS animation duration
            }
          }
          
          // Add click event listeners to all toggle buttons
          toggleButtons.forEach(button => {
            button.addEventListener('click', () => {
              toggleButtonState(button);
            });
            
            // For accessibility: support keyboard activation
            button.addEventListener('keydown', (e) => {
              if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                toggleButtonState(button);
              }
            });
          });
        });
      
Our JavaScript implementation provides: - A centralized function to handle the state toggle for all buttons - Proper updating of accessibility attributes when the state changes - Custom actions based on which button was toggled - Animation triggering when toggling to the active state - Support for keyboard navigation and activation - Clean handling of multiple toggle buttons on the same page

CSS

Let's style our toggle buttons to create a clean, interactive appearance:

        /* Icon toggle button base styles */
        .icon-toggle-btn {
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          background: transparent;
          border: none;
          border-radius: 8px;
          cursor: pointer;
          padding: 12px;
          transition: all 0.2s ease;
          position: relative;
          color: #64748b; /* Default icon color */
          font-family: inherit;
        }

        /* Hide icons that shouldn't be visible */
        .icon-toggle-btn .icon {
          opacity: 1;
          transition: opacity 0.2s ease, transform 0.2s ease;
        }

        .icon-toggle-btn .icon-active {
          position: absolute;
          top: 12px;
          opacity: 0;
          color: transparent;
        }

        /* Button hover and focus states */
        .icon-toggle-btn:hover {
          background-color: #f1f5f9;
          color: #334155;
        }

        .icon-toggle-btn:focus-visible {
          outline: 2px solid #3b82f6;
          outline-offset: 2px;
        }
      
Now let's style the active states of our buttons with different colors:

        /* Active state */
        .icon-toggle-btn.active {
          color: #3b82f6; /* Active color */
        }

        .icon-toggle-btn.active .icon-default {
          opacity: 0;
        }

        .icon-toggle-btn.active .icon-active {
          opacity: 1;
          color: #3b82f6;
        }

        /* Button specific colors */
        #like-button.active,
        #like-button.active .icon-active {
          color: #ef4444; /* Red for like */
        }

        #bookmark-button.active,
        #bookmark-button.active .icon-active {
          color: #3b82f6; /* Blue for bookmark */
        }

        #star-button.active,
        #star-button.active .icon-active {
          color: #eab308; /* Yellow for star */
        }

        #notify-button.active,
        #notify-button.active .icon-active {
          color: #8b5cf6; /* Purple for notifications */
        }
      
Finally, let's add the animation for toggling and responsive styles:

        /* Animation for toggling on */
        @keyframes pulse {
          0% { transform: scale(1); }
          30% { transform: scale(0.8); }
          60% { transform: scale(1.2); }
          100% { transform: scale(1); }
        }

        .icon-toggle-btn.animate .icon-active {
          animation: pulse 0.5s ease-in-out;
        }

        /* Responsive styles */
        @media (max-width: 480px) {
          .toggle-buttons-container {
            gap: 8px;
          }
          
          .toggle-btn-wrapper {
            min-width: 70px;
          }
          
          .icon-toggle-btn {
            padding: 8px;
          }
          
          .toggle-label {
            font-size: 12px;
          }
        }
      
These icon toggle buttons provide several advantages: - Visual clarity: The combination of icon changes and color shifts clearly indicates state - Intuitive feedback: The animation provides immediate confirmation of the user's action - Compact design: The vertical layout with icons and labels uses space efficiently - Consistent system: The uniform design can be extended to any binary action - Accessibility: Proper ARIA attributes and keyboard support ensure all users can interact - Visual differentiation: Different colors for different actions help users understand the meaning These toggle buttons are perfect for social interactions (like/favorite), content management (save/bookmark), preference settings, or any feature that requires a binary state toggle with clear visual feedback.

Whole code

<div class="toggle-buttons-container">
  <!-- Like Toggle Button -->
  <div class="toggle-btn-wrapper">
    <button class="icon-toggle-btn" id="like-button" aria-label="Like" aria-pressed="false">
      <svg class="icon icon-default" 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">
        <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z"></path>
      </svg>
      <svg class="icon icon-active" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78L12 21.23l8.84-8.84a5.5 5.5 0 0 0 0-7.78z"></path>
      </svg>
      <span class="toggle-label">Like</span>
    </button>
  </div>
  
  <!-- Bookmark Toggle Button -->
  <div class="toggle-btn-wrapper">
    <button class="icon-toggle-btn" id="bookmark-button" aria-label="Bookmark" aria-pressed="false">
      <svg class="icon icon-default" 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">
        <path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>
      </svg>
      <svg class="icon icon-active" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"></path>
      </svg>
      <span class="toggle-label">Save</span>
    </button>
  </div>
  
  <!-- Star Toggle Button -->
  <div class="toggle-btn-wrapper">
    <button class="icon-toggle-btn" id="star-button" aria-label="Star" aria-pressed="false">
      <svg class="icon icon-default" 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">
        <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
      </svg>
      <svg class="icon icon-active" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
      </svg>
      <span class="toggle-label">Star</span>
    </button>
  </div>
  
  <!-- Bell Toggle Button -->
  <div class="toggle-btn-wrapper">
    <button class="icon-toggle-btn" id="notify-button" aria-label="Enable notifications" aria-pressed="false">
      <svg class="icon icon-default" 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">
        <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
        <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
      </svg>
      <svg class="icon icon-active" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
        <path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path>
        <path d="M13.73 21a2 2 0 0 1-3.46 0"></path>
      </svg>
      <span class="toggle-label">Notify</span>
    </button>
  </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', () => {
  // Select all toggle buttons
  const toggleButtons = document.querySelectorAll('.icon-toggle-btn');
  
  // Function to toggle the state of a button
  function toggleButtonState(button) {
    const isPressed = button.getAttribute('aria-pressed') === 'true';
    const newState = !isPressed;
    
    // Update aria-pressed state
    button.setAttribute('aria-pressed', newState);
    
    // Add or remove active class for styling
    if (newState) {
      button.classList.add('active');
    } else {
      button.classList.remove('active');
    }
    
    // Get button ID to determine which icon is being toggled
    const buttonId = button.id;
    
    // You could trigger different actions based on the button id
    switch (buttonId) {
      case 'like-button':
        console.log(`User ${newState ? 'liked' : 'unliked'} the item`);
        break;
      case 'bookmark-button':
        console.log(`User ${newState ? 'saved' : 'removed'} the bookmark`);
        break;
      case 'star-button':
        console.log(`User ${newState ? 'starred' : 'unstarred'} the item`);
        break;
      case 'notify-button':
        console.log(`User ${newState ? 'enabled' : 'disabled'} notifications`);
        break;
    }
    
    // Create and play animation
    if (newState) {
      button.classList.add('animate');
      // Remove animation class after it completes
      setTimeout(() => {
        button.classList.remove('animate');
      }, 700); // Match this to your CSS animation duration
    }
  }
  
  // Add click event listeners to all toggle buttons
  toggleButtons.forEach(button => {
    button.addEventListener('click', () => {
      toggleButtonState(button);
    });
    
    // For accessibility: support keyboard activation
    button.addEventListener('keydown', (e) => {
      if (e.key === 'Enter' || e.key === ' ') {
        e.preventDefault();
        toggleButtonState(button);
      }
    });
  });
});
</script>

<style>
/* Container for toggle buttons */
.toggle-buttons-container {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  max-width: 800px;
  margin: 0 auto;
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* Wrapper for each toggle button */
.toggle-btn-wrapper {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 90px;
}

/* Icon toggle button base styles */
.icon-toggle-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  padding: 12px;
  transition: all 0.2s ease;
  position: relative;
  color: #64748b; /* Default icon color */
  font-family: inherit;
}

/* Hide icons that shouldn't be visible */
.icon-toggle-btn .icon {
  opacity: 1;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.icon-toggle-btn .icon-active {
  position: absolute;
  top: 12px;
  opacity: 0;
  color: transparent;
}

/* Button hover and focus states */
.icon-toggle-btn:hover {
  background-color: #f1f5f9;
  color: #334155;
}

.icon-toggle-btn:focus-visible {
  outline: 2px solid #3b82f6;
  outline-offset: 2px;
}

/* Toggle label */
.toggle-label {
  margin-top: 4px;
  font-size: 14px;
  font-weight: 500;
  transition: color 0.2s ease;
}

/* Active state */
.icon-toggle-btn.active {
  color: #3b82f6; /* Active color */
}

.icon-toggle-btn.active .icon-default {
  opacity: 0;
}

.icon-toggle-btn.active .icon-active {
  opacity: 1;
  color: #3b82f6;
}

/* Button specific colors */
#like-button.active,
#like-button.active .icon-active {
  color: #ef4444; /* Red for like */
}

#bookmark-button.active,
#bookmark-button.active .icon-active {
  color: #3b82f6; /* Blue for bookmark */
}

#star-button.active,
#star-button.active .icon-active {
  color: #eab308; /* Yellow for star */
}

#notify-button.active,
#notify-button.active .icon-active {
  color: #8b5cf6; /* Purple for notifications */
}

/* Animation for toggling on */
@keyframes pulse {
  0% { transform: scale(1); }
  30% { transform: scale(0.8); }
  60% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

.icon-toggle-btn.animate .icon-active {
  animation: pulse 0.5s ease-in-out;
}

/* Responsive styles */
@media (max-width: 480px) {
  .toggle-buttons-container {
    gap: 8px;
  }
  
  .toggle-btn-wrapper {
    min-width: 70px;
  }
  
  .icon-toggle-btn {
    padding: 8px;
  }
  
  .toggle-label {
    font-size: 12px;
  }
}
</style>
      
Thank you for reading this article.

Comments

More toggle-buttons

Similar

See also