photo of a hashtag made of cardboard
Photo by Jan Baborák on Unsplash

Animated Social Share Links

Learn how to build an animation for displaying social links using CSS

5 min read

In this article, we’ll be using CSS to animate a list of social sharing links. After clicking on a trigger button, the links expand out into a semi-circle with a slightly staggered animation effect.

The animation interaction was inspired by this Dribbble shot and all icons are from Font Awesome.

We’ll be using React for demonstration purposes, but this article can be applied to vanilla JS or any other library.

Getting Started

The component we’re building contains both the “trigger” button, as well as the social links themselves. The idea is that we toggle a few classes when the trigger is clicked, and the power of CSS handles everything else.

First, create a new React component named SocialShare.

There are two state values. isActive determines when the share link component has been clicked, and isComplete, as the name implies, is added shortly after to denote that the animation is complete. Both of these state values determine when CSS classes are added or removed.


const SocialShare = () => {
  const [ isActive, setIsActive ] = useState(false);
  const [ isComplete, setIsComplete ] = useState(false);

  const transitioningClass = isActive ? 'active' : 'inactive';

  return (...);
}

We also add a transitioningClass constant for the CSS class we’ll be toggling on and off.

Now we have some HTML to add.

The component returns a button to be used as the trigger for opening and closing the list of links. This button has an onClick event handler to toggle the isActive state we added above, and receives the transitioningClass we defined.


const SocialShare = () => {
  ...
  ...

  return (
    <div className="share">
      <button 
        className={`trigger ${transitioningClass}`}
        type="button"
        onClick={() => setIsActive(!isActive)}
      >
        <Share />
      </button>
    </div>
  );
}

Next, we need to add the social links and icons. There’s one for Twitter, LinkedIn, Facebook, Messenger, and Pinterest. Each anchor should have a corresponding CSS class.


const SocialShare = () => {
  ...
  ...

  return (
    <div className="share">
      <button 
        className={`trigger ${transitioningClass}`}
        type="button"
        onClick={() => setIsActive(!isActive)}
      >
        <Share />
      </button>
	    <div className={`share-options ${transitioningClass} ${isComplete && 'complete'}`}>
        <a href="#" className="twitter"><Twitter /></a>
        <a href="#" className="linkedin"><LinkedIn /></a>
        <a href="#" className="facebook"><Facebook /></a>
        <a href="#" className="messenger"><Messenger /></a>
        <a href="#" className="pinterest"><Pinterest /></a>
      </div>
    </div>
  );
}

Keep in mind, if you want a different number of links than above, you’ll need to do some manual CSS adjustments to update the positioning of each link.

Some projects have different ways of importing and using SVG icons. Here we assume the icons are imported and used as React components. Please reference the demo to see the full code.

Finally, let’s add a useEffect into the component. This updates the isComplete state value we defined to add a CSS class when the animation is starting. We’ll come back to the reasoning behind this soon.


const SocialShare = () => {
  ...
  ...

  useEffect(() => {
    if (isActive) {
      setIsComplete(true);
    } else {
      setIsComplete(false);
    }
  }, [isActive]);

  return ( ... );
}

Our React component is done, but so far all you’ll see are some icons on the page. Let’s add some styles!

CSS Styling and Layout

We’ll be using CSS nesting below. This is native in CSS now and should work just fine so long as you’re using a modern browser. To learn more about nested CSS, please check out Nesting in CSS.

First, we have the styles for buttons and the share div.


button {
  cursor: pointer;
  border: none;
  line-height: 1;
}

.share {
  margin: 260px auto;
  max-width: 400px;
  position: relative;
}

Next let’s define the .trigger styling and its hover effect.


.trigger {
  background: #2863DB;
  padding: 15px;
  border-radius: 50%;
  height: 60px;
  width: 60px;
  display: block;
  margin: auto;
  transition: transform 0.3s ease, box-shadow 0.3s ease, background 0.3s ease;
  transform-origin: 50% 50%;
  position: relative;
  z-index: 2;

  & svg {
    height: 30px;
    width: 30px;
    fill: #fff;
  }

  &:hover {
    transform: translateY(-5px);
    box-shadow: 0px 6px 10px 0px rgba(0, 0, 0, 0.2);
  }
}

If you noticed in the demo, the trigger should spin 360 degrees and get slightly smaller after being clicked.

We can do this by adding a CSS animation property when the active class is applied.


.trigger {
  ...
  ...

  &.active {
    animation: rotateClockwise 0.6s ease forwards;
    background: #6aa2ff;
    box-shadow: none;
  }
}

@keyframes rotateClockwise {
  0% {
    transform: rotate(0) scale(1);
  }

  100% {
    transform: rotate(360deg) scale(0.9);
  }
}

Let’s take a break and check the progress so far.

the social link trigger styling
the social link trigger styling

Now that the trigger is done, lets style and position the social links.

Each link is contained in a .share-options div. This div is absolutely positioned over the trigger and initially has a visibility of hidden and opacity of 0 in order to hide it when not active. We use flexbox to help with alignment.


.share-options {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  top: 50%;
  left: 0%;
  right: 0%;
  opacity: 0;
  height: 100%;
  width: 100%;
  visibility: hidden;
}

Each link should have a gradient background and be absolutely positioned.


.share-options {
  ...

  & a {
	  background: linear-gradient(165deg, hsla(283, 100%, 70%, 1) 0%, hsla(221, 81%, 54%, 1) 100%);
	  padding: 15px;
	  margin: 10px;
	  height: 70px;
	  width: 70px;
	  border-radius: 50%;
	  vertical-align: middle;
	  display: flex;
	  align-items: center;
	  position: absolute;
	
	  &:hover {
	    box-shadow: 0px 6px 10px 0px rgba(0, 0, 0, 0.2);
	  }
	}

  & svg {
    fill: white;
    height: 40px;
    width: 40px;
  }
}

Next, we have the layout for the links, as well as the hover state.

Each link is positioned in a semi-circle outwards from the trigger. We can accomplish this positioning by applying a CSS transform to each link when the share-options div receives the active class.


.share-options {
  ...

  &.active {
    opacity: 1;
    visibility: visible;
    top: 0;

    .twitter {
      transform: translate(-200%, -50%);

      &:hover {
        transform: translate(-200%, -50%) scale(1.2);
      }
    }

    .linkedin {
      transform: translate(-128%, -160%);

      &:hover {
        transform: translate(-128%, -160%) scale(1.2);
      }
    }

    .facebook {
      transform: translate(0%, -200%);

      &:hover {
        transform: translate(0%, -200%) scale(1.2);
      }
    }

    .messenger {
      transform: translate(128%, -160%);

      &:hover {
        transform: translate(128%, -160%) scale(1.2);
      }
    }

    .pinterest {
      transform: translate(200%, -50%);

      &:hover {
        transform: translate(200%, -50%) scale(1.2);
      }
    }
  }
}

Notice how the hover effect has some repetition of the translate positioning when defining the scale property. This is to hold the link in place when hovering. Without it, the link moves back to its original position.

the layout and styling of the social links
the layout and styling of the social links

Clicking the trigger button places each link into the correct position, so now let’s add the animation.

First, add the transition and transform properties to the share-options div. The cubic-bezier transition timing we’re using gives the links a slight “bounce” effect.


.share-options {
  ...

  & a {
    ...
    transition: transform 0.3s cubic-bezier(.47,1.64,.41,.8), box-shadow 0.3s ease;
    transform: scale(0.2);
  }
}

Since we already applied the positioning for each item, all we need to do is provide a slightly incrementing transition-delay. This allows for the staggered animation.


.share-options {
  &.active {
    ...

    .twitter {
      ...
      transition-delay: 0.1s;
    }

    .linkedin {
      ...
      transition-delay: 0.15s;
    }

    .facebook {
      ...
      transition-delay: 0.2s;
    }

    .messenger {
      ...
      transition-delay: 0.25s;
    }

    .pinterest {
      ...
      transition-delay: 0.3s;
    }
  }
}

The last thing to add is the scale transition for each anchor on hover.

The useEffect we added earlier was to apply the complete CSS class. Because we’ve already defined a transition-delay on each link, a separate class is needed to remove the delay when the animation is done. Without this, the scale transition for each link is delayed by whatever value was defined previously.


.share-options {
  ...

  &.active {
    ...

    &.complete {
      & a {
        transition-delay: 0s;
      }
    }
  }
}

Summary

This article demonstrated how to use CSS to create an animation that expands social sharing links into a semi-circle after clicking a trigger button. The article includes React code for the component and CSS styling for the trigger button and links, including positioning and animation effects.