avatar
sport_avatar

18%

$57,451

React progress halo

April 24, 2020

For one of my previous projects I got a task to add a progress ring around a user avatar as a visual representation of a user level. Honestly, it’s not stuff you want to make manually, so I started searching for some existing solutions. BTW, we’ve already had the avatar itself.
Unfortunately, I couldn’t find a simple and lightweight npm lib for it, so finally I made my own component. Npm package is here.
In this article, I will describe how to set a fancy progress halo around the user avatar in React project, using the above component.

For simplicity, let’s represent our avatar as styled image and import the progress-halo component:


  import React from 'react';
  import styled from 'styled-components';
  import ProgressHalo from 'progress-halo';
  import avatar_img from './avatar.png';
  
  const CustomAvatar = styled.img`
    max-width: 100px;
  `;
              

Next, add a wrapper for our components for a better positioning and our progress ring with some styles (as StyledProgressHalo):

         
  const Wrapper = styled.div`
    position: relative;
  `;
  
  const StyledProgressHalo = styled(ProgressHalo)`
    position: absolute;
    top: -10px;
    left: -10px;
  `;
              

The ring itself will be slightly bigger (radius * 2 = 120px) than the avatar and will be positioned in the foreground.
Next step is our progress avatar component:


  export function ProgressAvatar(props: ComponentProps) {
    const { progress, color, progressColor, radius = 60, width } = props;
    return (
      <Wrapper>
        <CustomAvatar src={avatar_img}/>
        <StyledProgressHalo
          progress={progress}
          color={color}
          progressColor={progressColor}
          radius={radius}
          width={width}
        />
      </Wrapper>
    );
  }
                

Let’s describe props which we use for StyledProgressHalo and for ProgressAvatar:


  interface ComponentProps {
    progress?: number,
    color?: string,
    progressColor?: string,
    radius?: number,
    width?: number,
  }
                

Progress - obviously, here we pass the current value of user progress from 1 to 100. In my case, I fetched it from the back-end alongside with the user’s data. We had 10 levels, so each level was 10% of progress.
Color - the background hex color of the ring. Progress color - a hex color of the progress.
Radius - in my case it is 60px, because according to the design, the progress ring was a slightly bigger than the image:

sample

Width - it’s the width of the progress ring. I would suggest to work a bit on the radius, width of the progress ring and a size of the avatar in order to find a better positioning and a proper composition.
Eventually, there is the last prop className, which is not used in this example, but you can use it for css styling.
That’s it, the final code of our ProgressAvatar component:


  import React from 'react';
  import styled from 'styled-components';
  import ProgressHalo from 'progress-halo';
  import avatar_img from './avatar.png';
  import './styles.css';
  
  const Wrapper = styled.div`
    position: relative;
  `;
  
  const CustomAvatar = styled.img`
    max-width: 100px;
  `;
  
  const StyledProgressHalo = styled(ProgressHalo)`
    position: absolute;
    top: -10px;
    left: -10px;
  `;
  
  
  interface ComponentProps {
    progress?: number,
    color?: string,
    progressColor?: string,
    radius?: number,
    width?: number,
  }
  
  export function ProgressAvatar(props: ComponentProps) {
    const { progress, color, progressColor, radius = 60, width } = props;
    return (
      <Wrapper>
        <CustomAvatar src={avatar_img}/>
        <StyledProgressHalo
          progress={progress}
          color={color}
          progressColor={progressColor}
          radius={radius}
          width={width}
        />
      </Wrapper>
    );
  }
                

I have to say a few words about css styling. If you need to use css, just add className props to each of the described components, look at the following example:


              
  .progress-avatar__wrapper {
     position: relative;  
  }
  
  .progress-avatar__image {
     max-width: 100px;  
  }
  
  .progress-avatar__halo {
     position: absolute !important;  /*need this to overwrite default inline style*/
     top: -10px;
     left: -10px;
  }
              

The only difference is that in case of css styling we use a position: absolute !important, in order to overwrite default inline styles of progress halo, which can’t be overwritten without it.
As a pleasant bonus, the progress halo component has animation for change progress. It makes a dynamic change of the level more pleasant. In future, I’m going to add a few extra features like a gradient progress color or tooltips.

I hope you will find these tips helpful if you get started adding a progress visualization to your website!