Creating A Stepper Component with `useState`
Tags: webdev, javascript, react, tutorial
Published: 2023-06-23 13:00:00

## Introduction
We've all seen a stepper before right? No, not the fitness machine that simulates walking up a flight of stairs. A **stepper** is a piece of UI that shows you where you are in a list of tasks, questions, steps, etc,. They provide a _wizard-like_ workflow and can are sometimes used as navigation. They're also pretty easy to create with React and the `useState` hook. 

Full disclosure, I didn't come up with the idea of this project on my own. I'm still refreshing my React knowledge with Jonas Schmedtmann's [React course](https://www.udemy.com/course/the-ultimate-react-course). This is a practice project from the course. Last week I wrote a post detailing how I created a developer profile card from the same course. If you're interested learning how I did it, be sure to [check it out](https://dev.to/ritabradley_dev/creating-a-versatile-developer-profile-card-with-react-333l)!

What I've been doing with these projects is pausing the video, and attempting to complete them on my own. I find this helps me find out what I already know while forcing me to challenge myself to figure out the things I don't. This is a recommended approach if you struggle with imposter syndrome like I do. Exploring your own solutions to tutorials is a great way to test and solidify your knowledge. Let's get started. 


## Prerequisites

In this post, I'm assuming you have a working knowledge of JavaScript and its array methods. I'm also assuming you know some React basics like JSX, how to create components, and how to pass props. In React, props (short for properties) are a way of passing data from parent components to child components. They make our components more versatile and reusable by allowing them to behave differently based on the input they receive. If you need a refresher on any of this, I recommended checking out the following resources: 

- MDN JavaScript [guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide) & [reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference)
- [freecodecamp.org](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/)
- [JavaScript30](https://javascript30.com/) by Wes Bos
- Codecademy's [React course](https://www.codecademy.com/learn/react-101)


## Getting Started with the Step Progress Component


![A screenshot of a step progress user interface component against a pink and purple radial gradient background](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bkfjlepdzev55g1vu69m.png)

Let's dive in and create our own Step Progress Component with React and useState.


### Setting up the Project

First, we need to set up a new React project. If you don't already have one, you can create a new one using Create React App. 

``` bash
npx create-react-app step-progress-component
```
> I normally use Vite for creating React projects, but since this tutorial called for CRA, I stuck with it.

Once you've created your React project, navigate to the project directory and start your local development server. 

``` bash
cd step-progress-component
npm start
```

You should now have a new React project running on `http://localhost:3000`.


### Remove boilerplate code

Create React App gives us a lot of code/files that we may not always need. In this case, we don't need `App.css`,  `App.test.js`, `reportWebVitals.js`, `setupTests.js`, nor `logo.svg`. In `index.js`, remove and trace of `reportWebVitals`. In `App.js` remove the imports for `App.css` and `logo.svg`. Then remove everything between the first `div`, and delete `className="App"`.

Jonas provided the CSS for this project, so we'll be replacing the code in `index.css` with that. All I added was the `.active` styling for buttons, and extra styling to the body to make it pretty.

``` css
* {
    box-sizing: border-box;
}

body {
    font-family: sans-serif;
    color: #333;
    min-height: 100vh;
    display: grid;
    place-content: center;
    background-image: radial-gradient(circle, #7950f2, #995ef5, #b36df8, #ca7dfb, #df8eff);
}

.steps {
    width: 600px;
    background-color: #f7f7f7;
    border-radius: 7px;
    padding: 25px 100px;
    margin: 100px auto;
}

.numbers {
    display: flex;
    justify-content: space-between;
}

.numbers > div {
    height: 40px;
    aspect-ratio: 1;
    background-color: #e7e7e7;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
}

.numbers .active,
button.active {
    background-color: #7950f2;
    color: #fff;
}

.message {
    text-align: center;
    font-size: 20px;
    margin: 40px 0;
    font-weight: bold;

    display: flex;
    flex-direction: column;
    align-items: center;
}

.buttons {
    display: flex;
    justify-content: space-between;
}

.buttons button {
    border: none;
    cursor: pointer;
    padding: 10px 15px;
    border-radius: 100px;
    font-size: 14px;
    font-weight: bold;

    display: flex;
    align-items: center;
    gap: 10px;
}

.buttons button span {
    font-size: 16px;
    line-height: 1;
}

h3 {
    margin: 0;
    text-transform: uppercase;
}
```


### Creating the Step component

Firstly, let's dive into our Step Component. This component accepts two props, styleClass and number.

``` jsx
export default function Step({ styleClass, number }) {
 return <div className={styleClass}>{number}</div>;
}
```

The `styleClass` prop allows us to apply conditional styling to our component depending on what step is active, and the `number` prop passes a number to the component based on the current step.

This component is quite simple, but it plays a key role in our application by rendering each step in the progress bar.


### Crafting the StepText Component

The `StepText` component is responsible for displaying the text associated with each step in our progress bar. We pass a single `text` prop to this component, which we then render within an `h3` tag.

``` jsx
export default function StepText({ text }) {
 return <h3>{text}</h3>;
}
```

This component is a fantastic example of the principle of "composition" in React, allowing us to keep our components small, focused, and reusable.


### Button, button, who's got the button?

Next, we'll move onto the `Button` component. This component will render our 'Next' and 'Previous' buttons, and will handle user interactions to move between steps.

``` jsx
export default function Button({ children, onClick, styleClass }) {
  return (
    <button className={styleClass} onClick={onClick}>
      <span>{children}</span>
    </button>
  );
}
```
The `onClick` prop that we pass to our button allows us to handle user clicks and thus manipulate the active step in our progress bar. The `children` prop allows us to pass the button text as children of the `Button` component.


## Bringing it all together

In `App.js`, we need to import all three components. 

> I recommend placing individual components in a `components` folder in the `src` directory. This makes for better organization in the long run. Since this is a smaller project, we can get away with not doing this.

### Adding Interactivity with `useState`

With our components ready, let's move on to creating an interactive stepper. For this, we'll be using React's `useState` hook. Hooks are a relatively new addition to React that allows us to use state and other React features in our functional components. `useState` is one of these hooks and it allows us to add state to our functional components. State can be thought of as a way to keep track of information in your application that can change over time and affect your app's behavior.

In our `App.js`, we'll start by importing `useState` from React and our three components: `Step`, `StepText`, and `Button`.

``` js
import { useState } from 'react';
import Step from './Step';
import StepText from './StepText';
import Button from './Button';
```

Then, let's define the text for each step of our progress bar. We'll store this in an array called `stepText`.

``` js
const stepText = ['Learn React ⚛️', 'Apply to jobs 💼', 'Get a job 🎉'];
```

### Creating the State for Our Stepper

Next, we're going to create our `step` state. We initialize it to 1 since we want to start at the first step. We use `setStep` to change the state.

```js
const [step, setStep] = useState(1);
```

### Handling Step Changes

After that, we'll create two functions `handleNext` and `handlePrevious`. These functions will allow us to go forward or backward in our progress bar when the next and previous buttons are clicked.

```js
const handleNext = () => {
  if (step < stepText.length) {
    setStep(step + 1);
  }
};

const handlePrevious = () => {
  if (step > 1) {
    setStep(step - 1);
  }
};

```

### Rendering Our Components

Finally, we'll render our components. We create a div for each step and conditionally apply the 'active' class to the current step. We also render the text for the current step and the previous and next buttons, again applying the 'active' class conditionally.

```jsx
return (
  <div className="steps">
    <div className="numbers">
      {stepText.map((_, index) => (
        <Step
          styleClass={step === index + 1 ? "active" : ""}
          key={`Step ${index + 1}`}
          number={index + 1}
        />
      ))}
    </div>
    <div className="message">
      <StepText text={stepText[step - 1]} />
    </div>

    <div className="buttons">
      <Button styleClass={step > 1 ? "active" : ""} onClick={handlePrevious}>
        Previous
      </Button>
      <Button
        styleClass={step < stepText.length ? "active" : ""}
        onClick={handleNext}
      >
        Next
      </Button>
    </div>
  </div>
);
```

And that's it! We've built a functional Step Progress Component using React and the `useState` hook. The full code for `App.js` looks like this:


``` jsx
import { useState } from "react";
import Step from "./components/Step";
import StepText from "./components/StepText";
import Button from "./components/Button";

const stepText = ["Learn React ⚛️", "Apply to jobs 💼", "Get a job 🎉"];

function App() {
  const [step, setStep] = useState(1);

  const handleNext = () => {
    if (step < stepText.length) {
      setStep(step + 1);
    }
    console.log(step);
  };

  const handlePrevious = () => {
    if (step > 1) {
      setStep(step - 1);
    }
    console.log(step);
  };

  return (
    <div className="steps">
      <div className="numbers">
        {stepText.map((_, index) => (
          <Step
            styleClass={step === index + 1 ? "active" : ""}
            key={`Step ${index + 1}`}
            number={index + 1}
          />
        ))}
      </div>
      <div className="message">
        <StepText text={stepText[step - 1]} />
      </div>

      <div className="buttons">
        <Button styleClass={step > 1 ? "active" : ""} onClick={handlePrevious}>
          Previous
        </Button>
        <Button
          styleClass={step < stepText.length ? "active" : ""}
          onClick={handleNext}
        >
          Next
        </Button>
      </div>
    </div>
  );
}

export default App;
```

## Conclusion

Learning React is all about understanding its core concepts, and useState is definitely one of them. By building this Step Progress Component, not only did we gain a better understanding of how useState works, but we also learned how to structure our code using components and how to pass props to make them more reusable. This is a great step forward in becoming a more proficient React developer. Keep practicing and you'll surely get there!


> If you want to see the stepper in action, check out my pen!

{% codepen https://codepen.io/ritabradley_dev/pen/OJaRvYd %}