DEV Community

Michael Burrows
Michael Burrows

Posted on • Updated on • Originally published at w3collective.com

Create a custom React star rating component

In this tutorial we’ll be building a custom React star rating component. This type of component allows users to give something a rating between 1 and 5 stars with a single mouse click.

Here’s how the completed component will look & function:

Alt Text

Let’s get started by setting up an application using Create React App:

npx creat-react-app star-rating

Then in the /src directory create a file for the component named StarRating.js. We’ll start with a bare bones component to test the setup then build out the full functionality:

import React, { useState } from "react";

const StarRating = () => {  
  return (<p>Hello World</p>);
};

export default StarRating;
Enter fullscreen mode Exit fullscreen mode

Next replace the contents of the App.js file to load in the component:

import StarRating from "./StarRating";
import "./App.css";

const App = () => {
  return (
    <div className="App">
      <StarRating />
    </div>
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Run the npm start command and test that the component is being loaded.

Now back to the StarRating.js file, first thing we need to do is have the component output 5 stars which we do by mapping over an array:

const StarRating = () => {
  return (
    <div className="star-rating">
      {[...Array(5)].map((star) => {        
        return (         
          <span className="star">&#9733;</span>        
        );
      })}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

&#9733; is the HTML entity code for a star icon but you could also use an icon library like Font Awesome here if you wanted. Next we need to add the functionality that sets the star rating when clicked. For this we’ll wrap the stars in a <button> and with a onClick() event:

const StarRating = () => {
  const [rating, setRating] = useState(0);
  return (
    <div className="star-rating">
      {[...Array(5)].map((star, index) => {
        index += 1;
        return (
          <button
            type="button"
            key={index}
            className={index <= rating ? "on" : "off"}
            onClick={() => setRating(index)}
          >
            <span className="star">&#9733;</span>
          </button>
        );
      })}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

We’re using the State hook to store the value (index) of the star clicked. Depending on the rating selected a class of either “on” or “off” is added, this will allow us to style the icons to give a visual representation of the rating selected.

And here is the CSS which we’ll add to the App.css file:

button {
  background-color: transparent;
  border: none;
  outline: none;
  cursor: pointer;
}
.on {
  color: #000;
}
.off {
  color: #ccc;
}
Enter fullscreen mode Exit fullscreen mode

With the CSS setup we have a functioning component that will show the star rating selected on click. For some added interactivity we’ll also implement a hover effect that indicates the rating that will be selected on click:

const StarRating = () => {
  const [rating, setRating] = useState(0);
  const [hover, setHover] = useState(0);
  return (
    <div className="star-rating">
      {[...Array(5)].map((star, index) => {
        index += 1;
        return (
          <button
            type="button"
            key={index}
            className={index <= (hover || rating) ? "on" : "off"}
            onClick={() => setRating(index)}
            onMouseEnter={() => setHover(index)}
            onMouseLeave={() => setHover(rating)}
          >
            <span className="star">&#9733;</span>
          </button>
        );
      })}
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

There you have it, a custom star rating component without the need for any additional dependencies or frameworks. As usual the source code for this project can be found on GitHub. Thanks for reading :)

Top comments (10)

Collapse
 
morskibg profile image
morskibg • Edited

Hi, good job ! Just to suggest option to reset rating back to 0 thru dbl click on any star :
onDoubleClick={() => {
setRating(0);
setHover(0);
}}

Collapse
 
venkateshpachigulla profile image
venkateshpachigulla

After clicking enter for one time then the hover is not working.

Collapse
 
danielmagar profile image
Daniel-Magar • Edited

Just change the code in className from THIS:
idx <= ((rating || hover) ? "on" : "off"

TO:

              idx <= ((rating && hover) || hover) ? "on" : "off"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
dewlucky profile image
Lucky Dewangan

Hey you can further simplify it, by this code, think twice why it works :)
idx <= hover ? "on" : "off"

This will work because the result from ((rating && hover) || hover) is decided by hover only.

Collapse
 
biloustrike profile image
Bilal

Since on leave back to rating here:
onMouseLeave={() => setHover(rating)}

you can just do:

idx <= hover ? "on" : "off"
Enter fullscreen mode Exit fullscreen mode
Collapse
 
shreyash101 profile image
shreyash101

hey, could u explain the logic/intuition behind this?

Collapse
 
debespindola profile image
Deborah Espíndola • Edited

This was so useful for my team! Thank you very much!

Collapse
 
kachidk profile image
Nwanguma Victor

This was very helpful, I was about to install a whole library !!! Thank you :)

Collapse
 
mehedihsiamt profile image
Mehedi Hasan Siam

Very Helpful article. Thanks to the writer.

Collapse
 
simphiwetebe profile image
SimphiweTebe

Very cool tutorial! It helped a lot, thanks