How To Build a Star Rating Using useState Hook
Learn how to create a star rating widget using the useState hook in React
Table of contents
Have you ever wondered how star ratings commonly seen on e-commerce websites or app stores are created?
Thousands of reviews are received every day, and many products and services across the web aren't complete without a star rating for receiving customer feedback and reviews.
Using this guide, you should be able to understand the simple process of building a star rating with React.
Prerequisites
Basic understanding of React and useState hook.
To complete this tutorial, you’ll need:
Node.js
- To create a local development environment.React
- To bootstrap the project.
Here is what a star rating component looks like:
Setting up the Project
Generate a React App using create-react-app
:
npx create-react-app star-rating
Install aStar
icon as dependencies:
npm install react-icons
You can also use an
SVG
in place of thereact-icons
Change into the new project directory:
cd star-rating
Now, you can run the React application:
npm start
Then, visit localhost:3000
in your web browser to see the React app.
1. Creating the Star component
In the src
, create a Star.jsx
file and populate it with the following:
import React from "react";
const Star = () => {
return (
<div className="star">
STAR
</div>
);
};
export default Star;
Now, import the Star
icon from react-icons
:
import { FaStar } from "react-icons/fa";
Substitute the mockup text STAR
with the JSX <FaStar />
:
import React from "react";
import { FaStar } from "react-icons/fa";
const Star = () => {
return (
<div className="star">
<FaStar />
</div>
);
};
export default Star;
This JSX displays a single star derived from react-icons
.
2. Rendering the Star
component
Remove default logic found in the App.jsx
and import the Star
.
import Star from "./Star";
function App() {
return (
<div className="App">
<Star />
</div>
);
}
export default App;
Now, you should see a star rendered in your app via localhost:3000
.
3. Adding useState
Hook to Star component
Here, we create two states to manage the star hover
and rating
states.
useState
hook allows handling of the state of the Star component.
import { useState } from "react";
const [rating, setRating] = useState(null);
const [hoverFill, setHoverFill] = useState(null);
4. Creating multiple copies of Star
icon
By default, star ratings are five. so, let's implement five stars by mapping through the existing single star.
[...Array(5)]
creates an array of length 5. Passing a map
function to this array return 5 different star icons.
{[...Array(5)].map((_, index) => {
return (
<button>
<FaStar />
</button>
);
Noticed the use of
(_, index)
, this is because we are not returning any item but making use of pre-existing one. Theindex
act as a unique identifier for the stars.
5. Handling hoverFill
and rating
states
The Star icon from react-icons
doesn't support eventhandling
. So, we need any <html>
tag that has inbuilt functionalities for eventhandlers
.
Wrap the Star icons within a <button>
tag and control the state
using specific events
.
The hoverFill
state is toggled by onMouseEnter
and onMouseLeave
props.
We add a rating to the hoverFill
state whenever we hover over the stars and also set it to null
when the mouse is moved away from it. TheonClick
function sets rating
to the number of star rating.
<button
key={index}
onMouseEnter={() => setHoverFill(ratingValue)}
onMouseLeave={() => setHoverFill(null)}
onClick={() => setRating(ratingValue)}
>
<FaStar />
</button>
6. Setting the button wrapper visibility
Next, we will hide the visibility of the button to make the Star
look better.
.star > button {
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
}
7. Handling the star look
The onChange
props handle the rating
state after onClick
event is passed.
Using a conditional statement, we will check the hoverFill
and rating
to determine whether to fill the star with the yellow-like color or set it to default. The hoverFill
decides the color of the star while the index
value decides the number of stars to be filled.
Let's set the value of rating
in ratingValue
variable.
let ratingValue = index + 1;
index + 1
because the array starts from "0".
<FaStar
size={80}
style={{
color:
ratingValue <= (hoverFill || rating) ? "#ffe101" : "#ccc",
}}
onChange={() => setRating(ratingValue)}
value={ratingValue}
/>
8. Final step
The complete code of the Star
component should look like this:
import React, { useState } from "react";
import { FaStar } from "react-icons/fa";
const StarRate = () => {
const [rating, setRating] = useState(null);
const [hoverFill, setHoverFill] = useState(null);
return (
<div className="star">
{[...Array(5)].map((_, index) => {
const ratingValue = index + 1;
return (
<button
key={index}
onMouseEnter={() => setHoverFill(ratingValue)}
onMouseLeave={() => setHoverFill(null)}
onClick={() => setRating(ratingValue)}
>
<FaStar
className="FaStar"
size={80}
style={{
color:
ratingValue <= (hoverFill || rating) ? "#ffe101" : "#ccc",
}}
onChange={() => setRating(ratingValue)}
value={ratingValue}
/>
</button>
);
})}
</div>
);
};
export default Star;
ratingValue <= (hoverFill || rating) ? "#ffe101" : "#ccc"
implies thathoverFill
andrating
states of all the stars including the last one will be toggled with the fill color#ffe101
or returned to the default color#ccc
as your mouse moves over them in the horizontal direction.
9. Bonus - Adding a Review label
To make the look aesthetic. Let's add a label for each rating.
Star ratings of 1,2,3,4,5
will display the review label of very bad, bad, okay, good, and excellent
respectively.
const getReviewLabel = (rating) => {
switch (rating) {
case 1:
return `Very bad ${String.fromCodePoint("0x1F922")}`;
case 2:
return `Bad ${String.fromCodePoint("0x1F97A")}`;
case 3:
return `Okay ${String.fromCodePoint("0x1F60C")}`;
case 4:
return `Good ${String.fromCodePoint("0x1F60A")}`;
case 5:
return `Excellent ${String.fromCodePoint("0x1F929")}`;
default:
return "";
}
};
The Emojis used are gotten from Unicode emoji charts. Each Unicode emoji is converted to the equivalent hex value and used as a string parameter inString.fromCodePoint()
method.
This is recommended because it is accessible by screen readers, unlike copy-paste emojis.
<h2 className="review-label">
{getReviewLabel(isHover > 0 ? isHover : rating)}
</h2>
The Star component's complete logic which includes the review label
should now look like this:
import React, { useState } from "react";
import { FaStar } from "react-icons/fa";
const StarRate = () => {
const [rating, setRating] = useState(null);
const [hoverFill, setHoverFill] = useState(null);
const [isHover, setIsHover] = useState(null);
const getReviewLabel = (rating) => {
switch (rating) {
case 1:
return `Very bad ${String.fromCodePoint("0x1F922")}`;
case 2:
return `Bad ${String.fromCodePoint("0x1F97A")}`;
case 3:
return `Okay ${String.fromCodePoint("0x1F60C")}`;
case 4:
return `Good ${String.fromCodePoint("0x1F60A")}`;
case 5:
return `Excellent ${String.fromCodePoint("0x1F929")}`;
default:
return "";
}
};
return (
<div className="star-wrapper">
<h2 className="review-label">
{getReviewLabel(isHover > 0 ? isHover : rating)}
</h2>
<div className="star">
{[...Array(5)].map((_, index) => {
const ratingValue = index + 1;
return (
<button
key={index}
onMouseOver={() => setIsHover(ratingValue)}
onMouseOut={() => setIsHover(null)}
onMouseEnter={() => setHoverFill(ratingValue)}
onMouseLeave={() => setHoverFill(null)}
onClick={() => setRating(ratingValue)}
>
<FaStar
className="FaStar"
size={80}
style={{
color:
ratingValue <= (hoverFill || rating)
? "#ffe101"
: "#ccc",
}}
onChange={(ratingValue) => setRating(ratingValue)}
value={ratingValue}
/>
</button>
);
})}
</div>
</div>
);
};
export default Star;
Add these Styling to the index.css
file:
#root,
html,
body {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.App {
display: flex;
justify-content: center;
align-items: center;
text-align: center;
width: 100vw;
height: 100vh;
}
.star-wrapper {
position: relative;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.review-label {
position: absolute;
margin-top: -100px;
}
.star > button {
background-color: transparent;
border: none;
cursor: pointer;
outline: none;
}
@media screen and (max-width: 450px) {
.FaStar {
width: 40px;
}
}
Conclusion
And with that being said, you have just learned how to create a star rating component with React. You can find the complete source code in this codesandbox.
Thank you very much for taking the time to read, I hope you found this helpful. Feel free to share and check other articles on my blog.