Unlock the Power of Custom SVG Loading Animations

The Magic of SVG

Scalable Vector Graphics (SVG) have become increasingly popular in recent years, and for good reason. SVGs offer a lightweight, scalable, and flexible way to create graphics that can be used across various devices and platforms. When it comes to loading animations, SVGs offer a unique opportunity to create custom, engaging, and interactive experiences.

From Icon to Animation

Let’s start with a simple SVG icon from The Noun Project. We’ll use this icon as a starting point to create a custom loading animation. The first step is to optimize the icon’s markup by removing unnecessary code and assigning descriptive IDs to the head and body parts.

<svg viewBox="0 0 24 24">
  <g id="head">
    <circle cx="12" cy="10" r="3" />
  </g>
  <g id="body">
    <rect x="8" y="14" width="8" height="6" rx="1" />
  </g>
</svg>

The Power of feFlood and feOffset

To create a loading animation, we’ll use SVG filters, specifically feFlood and feOffset. feFlood is used to fill the icon with a color, while feOffset creates an offset of the image. By animating the dy attribute of feOffset, we can create a loading animation that moves from top to bottom.

<svg viewBox="0 0 24 24">
  <filter id="loading-filter">
    <feFlood flood-color="#fff" />
    <feOffset in="SourceGraphic" dx="0" dy="10" />
  </filter>
  <g filter="url(#loading-filter)">
    <g id="head">
      <circle cx="12" cy="10" r="3" />
    </g>
    <g id="body">
      <rect x="8" y="14" width="8" height="6" rx="1" />
    </g>
  </g>
</svg>

Creating a Generic Loading Component

Now that we have a basic understanding of how SVG filters work, let’s create a generic loading component using React. This component will take any SVG paths as its basis and allow us to customize the animation direction, speed, and color.

import React from 'eact';

const LoadingComponent = ({ paths, direction, speed, color }) => {
  return (
    <svg viewBox="0 0 24 24">
      <filter id="loading-filter">
        <feFlood flood-color={color} />
        <feOffset in="SourceGraphic" dx="0" dy={direction === 'top'? '-10' : '10'} />
      </filter>
      <g filter="url(#loading-filter)">
        {paths}
      </g>
    </svg>
  );
};

export default LoadingComponent;

Customizing the Animation

With our loading component in place, we can customize the animation to suit our needs. We can change the animation direction, speed, and color to create a unique experience. We can also add additional props to control the animation’s behavior, such as repeat count and animation duration.

import React from 'eact';
import LoadingComponent from './LoadingComponent';

const MyLoadingAnimation = () => {
  return (
    <LoadingComponent
      paths={
        <>
          <circle cx="12" cy="10" r="3" />
          <rect x="8" y="14" width="8" height="6" rx="1" />
        </>
      }
      direction="bottom"
      speed="fast"
      color="#fff"
    />
  );
};

Taking it to the Next Level

By using CSS classes and React state management methods, we can take our loading animation to the next level. We can create a more dynamic and interactive experience by controlling the animation’s behavior based on user interactions.

.loading-animation {
  transition: all 0.3s ease-in-out;
}

.loading-animation:hover {
  transform: scale(1.1);
}
import React, { useState } from 'eact';
import LoadingComponent from './LoadingComponent';

const MyLoadingAnimation = () => {
  const [animationState, setAnimationState] = useState('idle');

  const handleMouseOver = () => {
    setAnimationState('hover');
  };

  const handleMouseOut = () => {
    setAnimationState('idle');
  };

  return (
    <LoadingComponent
      paths={
        <>
          <circle cx="12" cy="10" r="3" />
          <rect x="8" y="14" width="8" height="6" rx="1" />
        </>
      }
      direction="bottom"
      speed="fast"
      color="#fff"
      className={animationState === 'hover'? 'loading-animation' : ''}
      onMouseOver={handleMouseOver}
      onMouseOut={handleMouseOut}
    />
  );
};

Leave a Reply