Create a neumorphic progress bar in React
Tags: react, css
Published: 2022-05-31 20:11:28

**Written by [Emmanuel Odioko](https://blog.logrocket.com/author/emmanuelodioko/)✏️**

## Introduction

We have all come across a progress bar on a mobile device at least once, such as while installing anything from Google. 

Our goal in this article is to build an animated, neumorphic progress bar using React and CSS. The progress bar graphics will be accompanied by a textual representation of the progress in a percentage format ranging from 1–100. 

At the end of this tutorial, this is what we should have: ![Neumorphic Progress Bar](https://blog.logrocket.com/wp-content/uploads/2022/05/neumorphic-progress-bar.gif) 

In this article, we will learn how to build and style a neumorphic progress bar in React through the following sections:

*   [What is neumorphism?](#what-is-neumorphism)
*   [Setting up the development area](#setting-up-the-development-area)
*   [Properties of neumorphism](#properties-of-neumorphism)
*   [Create a `progress-bar` component](#create-a-progress-bar-component)
    *   [Create a neumorphic circle](#create-a-neumorphic-circle)
    *   [Styling with CSS](#styling-with-css)
*   [Adding the neumorphism effect](#adding-the-neumorphism-effect)
*   [Implementing the progress bar](#implementing-the-progress-bar)
*   [Displaying numerical progress with the `useState` and `useEffect` React Hooks](#displaying-numerical-progress-with-the-usestate-and-useeffect-react-hooks)

## What is neumorphism?

Neumorphism, also known as soft UI or the improvement of skeuomorphism, uses highlights and the `box-shadow` properties in CSS to make elements appear as if they float above the UI. 

If you know skeuomorphism, well, neumorphism is the new version of it. It is a product of flat and skeuomorphic designs. According to many resources out there, [Alexander Plyuto](https://dribbble.com/alexplyuto) is the father of this design, as he was the first to post a design using this style on dribble in 2019.

## Setting up the development area

### Prerequisites

Readers should have foreknowledge of [using SVGs in React](https://blog.logrocket.com/how-to-use-svgs-in-react/) and should also install:

*   React 18
*   Node.js ≥ v16.14.0

The first step to getting our project running is to create a folder for the project. I named mine `progress-bar`. 

Install React. I will do this by running this in my code editor:

```bash
npx create-react-app progress-bar @version 18
```

Change into the `progress-bar` folder and run:

```bash
npm start
```

Our React app should show up in your browser. Lastly, to get everything all set, delete the unneeded files and everything returned in our JSX.

## Properties of neumorphism

This eye-catching design is possible thanks to one major CSS property used in its development: the `box-shadow`. It’s advisable to [know your way around the `box-shadow` property] (https://blog.logrocket.com/three-ways-style-css-box-shadow-effects/) in CSS, because there is literally no way to implement neumorphism without this property. 

Here’s a quick refresher in case you need it: ![Properties Of Neumorphism](https://blog.logrocket.com/wp-content/uploads/2022/05/properties-of-neumorphism.png)

## Create a `progress-bar` component <a name="create-a-progress-bar-component"></a>

There are three major steps to achieving our goal:

1.  Create a neumorphic circle
2.  Create an SVG circle
3.  Add JavaScript functionality

### Create a neumorphic circle

We will need a neumorphic component to get started; we can name it `Neumorphism.js`. This component will have two `div`s, which have `classNames` attached to them for styling. 

Let’s import these into our main `App.js` to enable it to render in browsers at `localhost:3000`.

```javascript
//IMPORT COMPONENT
import React from 'react';
import Neumorphism from './Neumorphism';
import './App.css';

function App() {
 return (
   <main>
     <Neumorphism />
   </main>

 );
}

export default App;
```

Our component file should look like this:

```javascript
//NEUMORPHISM.JS

import React from 'react';
import './App.css';

function App() {
 return (
   <main className='container'>
     <div className="outside-progress-bar">
    <div className='inside-progress-bar'>
      <p> Neurmophism</p>
    </div>
   </div>
   </main>
 );
}
```

Over with the `div`s, we need the styling and animation for this application.

### Styling with CSS

The first step of our project is creating a neumorphic circle in our `neumorphism.js` component. Since we are creating a progress bar, centering our `div` is advisable. Let's get it done.

```css
.container {
   height: 100Vh;
   display: flex;
   align-items: center;
   justify-content: center;
   background-color: rgb(178, 190, 181);
}

//you can also add 30px of padding to center the container
```

## Adding the neumorphism effect

For our neumorphic effect, we’ll need to create two circles of the dimensions 160px and 140px, respectively, to display the progression effect. Let's get that done by adding basic styles to our `classNames`:

```css
.circle1 {
   height: 160px;
   width: 160px;
   border: 1px solid black;
   border-radius: 50%;
   padding: 3%;
}

.circle2 {
   height: 140px;
   width: 140x;
   border: 1px solid black;
   border-radius: 50%;
   height: 100%;
}
```

This is where we add a `box-shadow` to create the effects of neumorphism on our circle:

```css
.circle1 {
   height: 160px;
   width: 160px;
   border-radius: 50%;
   padding: 3%;
   box-shadow: -3px -3px 10px #ffffff73, 
               2px 5px 5px rgba(94, 104, 121, 288);
}

.circle2 {
   height: 140px;
   width: 140x;
   border-radius: 50%;
   height: 100%;
   box-shadow: -3px -3px 10px #ffffff73, 
               inset 1px 3px 5px rgba(94, 104, 121, 288);
}
```

![Adding Neumorphism Effect](https://blog.logrocket.com/wp-content/uploads/2022/05/adding-neumorphism-effect.png) Undoubtedly, this looks really great.

## Implementing the progress bar

We need to display a number that we can add functionality to, so it can display the percentage of our app’s progression. A `div` and styles are needed to accomplish this.

```html
<div>
   <p>100%</p>
</div>
```

```css
//center the paragraph

display: flex;
align-items: center;
justify-content: center;
```

![Implementing Progress Bar](https://blog.logrocket.com/wp-content/uploads/2022/05/implementing-progress-bar.png)

### Using SVGs

Now, we’ll use [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG) tags in React to fit into our neumorphic circle and display our progression. 

How are we able to make a circle that would fit in our neumorphic circle? It's logical to get the size of the circle, which can be gotten from the browser's console using the `ctrl+shift+i` command in the browser. ![Using SVGs To Display Progress](https://blog.logrocket.com/wp-content/uploads/2022/05/using-svgs-to-display-progress.gif) 

In our case, we have the `outer-circle` set to `200px` by `200px`, and the `inner-circle` set to `160px` x `160px`, with padding of `20px`. This gives us an idea of exactly what the dimensions of our SVG circle should be. 

Let's get this done. Here are the steps:

1.  First, we create a component for our SVG
2.  Then, get the SVG tag in our JSX
3.  Lastly, we input the dimensions of the circle [`cx`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cx), [`cy`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/cy), and [`r`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/r) CSS attribute

```javascript
import React from 'react';
import './progress.css';

function Progress(){
 return(
   <main className='container'>
       <div>
       <svg  className='circle'>
         <circle cx="100px" cy="100px" r="90px"  />
       </svg>
     </div>
   </main>
)
}

export default Progress
```

We need to import this component into our main `App.js`, so we can render it in our browser as we did earlier.

```javascript
import React from 'react';
import Neumorphism from './Neumorphism';
import Progress from './Progress';
import './App.css';

function App() {
 return (
   <main>
     <Neumorphism />
     <Progress />
   </main>

 );
}

export default App;
```

Here is what it looks like in our browser now: ![Example In Browser](https://blog.logrocket.com/wp-content/uploads/2022/05/example-in-browser.png) 

At this point, we need to make our SVG circle fit in our neumorphic circle above. With no doubt, the `position-absolute` CSS property will get the job done fastest.

```css
.circle {
       height: 300px;
       width: 300px;
       position: absolute;
       bottom: 20%;
       right: 34.3%;
   }
```

![Making SVG Circle Fit Neumorphic Circle](https://blog.logrocket.com/wp-content/uploads/2022/05/making-svg-circle-fit-neumorphic-circle.png) I reduced the height and width of the circle to show how `position-absolute` gets the job done. 

We obviously can’t leave the SVG display progression over our neumorphic circle while it’s filled, which takes us to our next step. 

Set the fill to `none` and add a stroke of `20px` to fit in perfectly:

```css
stroke-width: 20px;
fill: none;
stroke: black;
```

![Editing Fill And Font](https://blog.logrocket.com/wp-content/uploads/2022/05/editing-fill-and-font.png) Now, let’s add a blur to the stroke, just because it makes it more attractive:

```css
stroke: rgba(0, 0, 0, 0.1);
```

![Adding Blur](https://blog.logrocket.com/wp-content/uploads/2022/05/adding-blur.png)

Our next step is to animate our stroke. Using a [`stroke-dasharray`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray) to trace out the pattern of dashes used in our circle, we’ll outline the animation of this shape more easily. In our case, it is `565px`.

![We tried 400 and we got this.](https://blog.logrocket.com/wp-content/uploads/2022/05/animation-with-400px.png)*We tried 400 and we got this*

![565 is the perfect match.](https://blog.logrocket.com/wp-content/uploads/2022/05/animation-with-565px.png)*565 is the perfect match.*

We’ll also use a [`stroke-dashoffset`](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset) to take off whatever the `stroke-dasharray` has rendered. We needed the `stroke-dasharray` because, when the `stroke-dasharray` renders the full shape of the circle, the offset takes the rendered stroke-dasharray off so it can be refilled by animation. We will set this to 565px in order to allow animation perform the refilling progression. 

Our last step is to add the `animation` property to the SVG circle. In my case, I named it `progression` and gave it `1s` to progress forward. We also need to set `@keyframes` for our progression to be `100%`, and our `stroke-dashoffset` to `0`, to get it animated. Below are the styles added:

```css
// Styles
{ 
stroke-dasharray: 565px;
   stroke-dashoffset: 565px;
   animation: progress 1s linear forwards;
}

@keyframes progress {
   100% {
       stroke-dashoffset: 0;
   }
}
```

Now, whenever we refresh, we have our progress bar well animated. ![Animated Progress Bar](https://blog.logrocket.com/wp-content/uploads/2022/05/animated-progress-bar.gif)

## Displaying numerical progress with the `useState` and `useEffect` React Hooks <a name="displaying-numerical-progress-with-the-usestate-and-useeffect-react-hooks"></a>

You may have noticed that, despite creating the animation, our progress bar displays a static number of `100%`. In order to get the correct amount of progression displayed numerically, we need to use the `useState` and `useEffect` Hooks to make it display our progress in percentages. These Hooks will be imported into our `neumorphism.js` component.

```javascript
import React, { useState,useEffect } from 'react';
```

Using the `useState` Hook, our state will be a number, preferably starting from `0`.

```javascript
const [progress, setprogress] = useState(0);
```

Next, we need a `useEffect` Hook with no dependencies, so we create an interval to run every `2ms`. The basic job of this interval is to set our progress. To have better control, we use the callback form from the set progress to increment by `1`. 

To clear up this interval and avoid an infinite loop, we employ an `if` statement, so when it reaches `98` or it equates to `100`, it stops running, and we return the value, which should be `100%`. 

Lastly, we need to pass our progress in our JSX, so we can see it increment. Let's see this all done.

```jsx
import React, { useState,useEffect } from 'react'; 
import './App.css';
function Neumorphism() {
 const [progress, setprogress] = useState(0);

useEffect(()=>{
 const interval= setInterval(()=>{
   setprogress((oldvalue)=>{

     let newValue=oldvalue + 1;

     if(newValue>98){
       clearInterval(interval);
     }

     return newValue;

   })
 },20)
 },[]);

 return (
   <main className='container'>
     <div className="circle1">
       <div className='circle2'>
         <div>
           <p className='text'>{progress}%</p>
         </div>
       </div>
     </div>
   </main>
 )
}

export default Neumorphism;
```

Here is what we finally have: ![Final Animation](https://blog.logrocket.com/wp-content/uploads/2022/05/final-animation.gif)

## Conclusion

We have been able to build a progress bar with a neumorphic effect. In our case, we used it to style a progress bar to display downloaded files. Having this type of neumorphic design in your application makes your UI more attractive, and given how easy it can be to implement in your existing React apps, I hope you try it out soon.

---

## Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, [try LogRocket](https://www2.logrocket.com/react-performance-monitoring). 

[![LogRocket signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://www2.logrocket.com/react-performance-monitoring)

[LogRocket](https://www2.logrocket.com/react-performance-monitoring) is like a DVR for web and mobile apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.