Liveness Badge for Profile Pictures with TailwindCSS

by||2 min read
Liveness Badge
Liveness Badge

Recently I saw the "liveness" Badge on Twitter which is showing a pulsating ring around a profile picture when the account is streaming. I asked myself how this feature would be implemented in TailwindCSS. here are the two solutions I came up with:

Liveness Badge with ReactJS and TailwindCSS

Let's take a naive approach and throw in a React Component. This way we can control when and how the styles will change. We will use TailwindCSS to style our component, which I will name ProfilePicture.js:

import React, {useEffect, useState, useRef} from 'react'
import './ProfileImage.css'

const ProfileImage = () => {

  const [liveness, setLiveness] = useState(false);
  const liveRef = useRef(false);
  
  useEffect(() => {
    const interval = setInterval(() => {
      liveRef.current = !liveRef.current;
      setLiveness(liveRef.current);
    }, 1500);
    return () => {
      clearInterval(interval);
    }
  }, []);

  const outerRingColorClasses = liveness ? 'border-indigo-700' : 'border-indigo-900'
  const outerRingClasses = `duration-700 delay-250 relative h-16 w-16 rounded-full border-[3px] p-[3px] trnasition-colors ${outerRingColorClasses}`;

  const innerRingColorClasses = liveness ? 'border-indigo-500' : 'border-indigo-700'
  const innerRingClasses = `duration-700 absolute inset-0 rounded-full border-4 p-4 trnasition-colors ${innerRingColorClasses}`;


  return (
    <div className={outerRingClasses}>
      <div className={innerRingClasses}>
        <div className='absolute inset-0 rounded-full profile-image' />
      </div>
    </div>
  )
}

export default ProfileImage

For simplicity, I will use a single profile picture in the custom CSS. This can be customized later to a dynamic user profile picture.

The content of ProfilePicture.css is as follows:

.profile-image {
    background-image: url('./profile.jpg');
    background-size: cover;
}

To have a pulse effect we use an effect with an interval to set our internal state which then will define the classes we use.

Regarding the HTML, we pack our image inside two outer divs to show our pulsating border animation.

Liveness Badge with plain TailwindCSS

Even if the solution with ReactJS is working, it depends on JavaScript code which will update the state and therefore the style in the DOM element. With TailwindCSS we have a special animation for this: pulse.

Instead of nesting our image into two divs with borders, we place it centered in a div, giving some space to show borders around (with inset-[x]). Aside our image we can now place two divs, absolutely positioned to our main div. Those two divs can now be separately animated:

export const ProfileImageNoJS = () => (
  <div className='relative h-16 w-16 rounded full'>
    <div className='absolute rounded-full inset-0 border-indigo-700 border-[3px] transition delay-1000 animate-pulse' />
    <div className='absolute rounded-full inset-[3px] border-indigo-400 border-4 animate-[pulse_2s_ease-in-out_infinite]' />
    <div className='absolute inset-[6px] rounded-full profile-image z-20' />
  </div>
)

As you can see, this code is much more readable and does not depend on JavaScript (out of simplicity I have exported a ReactJS component. But this code can be used in a HTML template as well).

Another advantage of this code is as well the performance. We keep the animation to the browser, since our animation only takes place in CSS. The DOM is not touched here because we do not use any timing functions in JavaScript with according DOM-Node updates.

Thank you for reading this far! Let’s connect. You can @ me on Twitter (@debilofant) with comments, or feel free to follow. Please like/share this article so that it reaches others as well.

© Copyright 2022 - Ersocon - All rights reservedVer. 2.3.6.9