Build a Simple React JavaScript Star Rating Component: A Beginner’s Guide

In today’s digital landscape, user feedback is crucial. Websites and applications rely heavily on user ratings to gauge satisfaction, guide decisions, and improve services. Implementing a star rating component allows users to express their opinions quickly and efficiently. This tutorial will guide you through building a simple, yet effective, star rating component using ReactJS. This is a perfect project for beginners and intermediate developers looking to expand their React skills and create interactive user interface elements. We’ll cover everything from the initial setup to handling user interactions and styling the component.

Why Build a Star Rating Component?

Star ratings are a universally recognized way to gather user feedback. They’re intuitive, easy to understand, and provide a quick snapshot of user sentiment. Here’s why building a star rating component is valuable:

  • Enhances User Experience: Allows users to provide feedback with a simple click.
  • Provides Valuable Data: Offers a quantifiable way to measure user satisfaction.
  • Improves Decision-Making: Helps in understanding what works and what needs improvement.
  • Increases Engagement: Encourages user interaction and participation.

Prerequisites

Before we dive in, make sure you have the following:

  • Node.js and npm (or yarn) installed on your system.
  • A basic understanding of HTML, CSS, and JavaScript.
  • Familiarity with ReactJS concepts like components, props, and state.
  • A code editor (like VS Code, Sublime Text, or similar) to write your code.
  • A browser to view your React application.

Setting Up the React Project

Let’s start by creating a new React project using Create React App. Open your terminal and run the following command:

npx create-react-app react-star-rating-component
cd react-star-rating-component

This command creates a new React application named react-star-rating-component. The cd command changes your directory into the newly created project folder. Now, start the development server:

npm start

This will open your React application in your default web browser, usually at http://localhost:3000.

Component Structure

Our star rating component will consist of a few key parts:

  • Stars: The visual representation of the stars (e.g., five stars).
  • State: A state variable to track the current rating (the number of stars selected).
  • Event Handlers: Functions to handle user interactions (e.g., clicking on a star).

Creating the Star Rating Component

Let’s create the component file. Inside the src directory, create a new file named StarRating.js. This is where we will build our component. First, let’s create a basic component structure:

// src/StarRating.js
import React, { useState } from 'react';

function StarRating() {
  const [rating, setRating] = useState(0);

  return (
    <div>
      {/* Stars will go here */}
    </div>
  );
}

export default StarRating;

In this code:

  • We import useState from React to manage the component’s state.
  • We declare a functional component called StarRating.
  • We use useState(0) to initialize the rating state variable to 0. This variable will store the current rating value.
  • We return a div element, which will be the container for our star rating component.

Adding the Star Icons

Next, we need to add the star icons. We can use any star icon, but for simplicity, we’ll use a simple Unicode character. Inside the StarRating component’s return statement, let’s add the star icons using a loop:

// src/StarRating.js
import React, { useState } from 'react';

function StarRating() {
  const [rating, setRating] = useState(0);
  const totalStars = 5;

  return (
    <div>
      {Array.from({ length: totalStars }, (_, index) => (
        <span
          key={index}
          style={{
            cursor: 'pointer',
            fontSize: '2rem',
            color: index < rating ? 'gold' : 'gray',
          }}
          onClick={() => setRating(index + 1)}
        >
          ★ {/* Unicode star character */}
        </span>
      ))}
    </div>
  );
}

export default StarRating;

Here’s what changed:

  • We added a totalStars variable to define the total number of stars.
  • We used Array.from() and a map function to generate an array of span elements, each representing a star.
  • Each span has a key prop (required for iterating through elements in React) and inline styles for the cursor, font size, and color.
  • The color is set to ‘gold’ if the star’s index is less than the current rating, otherwise it’s set to ‘gray’. This visualizes the selected stars.
  • We added an onClick event handler to each star. When clicked, it calls setRating(index + 1), updating the rating state with the clicked star’s index (plus 1, because indexes start at 0).
  • We used the Unicode star character ★ to represent the star icon.

Integrating the Component

To use the StarRating component, open src/App.js and import and render it:

// src/App.js
import React from 'react';
import StarRating from './StarRating';

function App() {
  return (
    <div className="App">
      <h1>React Star Rating Component</h1>
      <StarRating />
    </div>
  );
}

export default App;

Now, when you save the files and check your browser, you should see five gray stars. When you click on a star, it should turn gold, and the stars to its left should also turn gold, reflecting the selected rating.

Adding Hover Effects

Let’s add a hover effect to show which stars will be selected when the user hovers over them. We’ll use the onMouseEnter and onMouseLeave events to achieve this. Add a new state variable to temporarily store the hovered rating.


// src/StarRating.js
import React, { useState } from 'react';

function StarRating() {
  const [rating, setRating] = useState(0);
  const [hoverRating, setHoverRating] = useState(0);
  const totalStars = 5;

  return (
    <div>
      {Array.from({ length: totalStars }, (_, index) => (
        <span
          key={index}
          style={{
            cursor: 'pointer',
            fontSize: '2rem',
            color: index < (hoverRating || rating) ? 'gold' : 'gray',
          }}
          onClick={() => setRating(index + 1)}
          onMouseEnter={() => setHoverRating(index + 1)}
          onMouseLeave={() => setHoverRating(0)}
        >
          ★
        </span>
      ))}
    </div>
  );
}

export default StarRating;

Here’s what changed:

  • We added a hoverRating state variable, initialized to 0.
  • In the style, we now check index < (hoverRating || rating). This means that the star will be gold if either the hoverRating is greater than the star’s index, or if the rating is greater.
  • We added onMouseEnter and onMouseLeave event handlers to each star.
  • onMouseEnter sets the hoverRating to the star’s index + 1 (representing the star’s value).
  • onMouseLeave resets the hoverRating to 0 when the mouse leaves the star.

Adding Read-Only Mode (Optional)

Sometimes, you want to display the star rating without allowing users to change it. This is useful for displaying the average rating of a product or service. Let’s add a readOnly prop to our component.


// src/StarRating.js
import React, { useState } from 'react';

function StarRating({ rating: initialRating = 0, readOnly = false, onRatingChange }) {
  const [rating, setRating] = useState(initialRating);
  const [hoverRating, setHoverRating] = useState(0);
  const totalStars = 5;

  const handleStarClick = (index) => {
    if (!readOnly) {
      setRating(index + 1);
      if (onRatingChange) {
        onRatingChange(index + 1);
      }
    }
  };

  return (
    <div>
      {Array.from({ length: totalStars }, (_, index) => (
        <span
          key={index}
          style={{
            cursor: readOnly ? 'default' : 'pointer',
            fontSize: '2rem',
            color: index < (hoverRating || rating) ? 'gold' : 'gray',
          }}
          onClick={() => handleStarClick(index)}
          onMouseEnter={() => !readOnly && setHoverRating(index + 1)}
          onMouseLeave={() => !readOnly && setHoverRating(0)}
        >
          ★
        </span>
      ))}
    </div>
  );
}

export default StarRating;

Here’s what changed:

  • The component now accepts two props: initialRating (defaulting to 0) and readOnly (defaulting to false). We also accept an onRatingChange prop, which is a callback function that will be called whenever the rating changes.
  • The handleStarClick function encapsulates the logic for handling star clicks and only allows updating the rating if readOnly is false. It also calls the onRatingChange callback if it exists.
  • The cursor style is set to ‘default’ if readOnly is true, and ‘pointer’ otherwise.
  • The onMouseEnter and onMouseLeave events are only attached if readOnly is false.

To use the readOnly prop, you can modify your App.js file:


// src/App.js
import React from 'react';
import StarRating from './StarRating';

function App() {
  return (
    <div className="App">
      <h1>React Star Rating Component</h1>
      <StarRating />  {/* Editable rating */}
      <StarRating rating={3} readOnly={true} /> {/* Read-only rating with a rating of 3 */}
    </div>
  );
}

export default App;

Adding Styling with CSS

While the inline styles work, it’s best practice to separate styling from your component logic. Let’s create a CSS file to style our component. Create a new file named StarRating.css in the src directory and add the following CSS:


.star-rating-container {
  display: inline-flex;
  align-items: center;
}

.star-rating-container span {
  cursor: pointer;
  font-size: 2rem;
  color: gray;
}

.star-rating-container span.active {
  color: gold;
}

.star-rating-container span:hover {
  color: gold;
}

Here’s what the CSS does:

  • .star-rating-container: This class provides a container for the stars.
  • .star-rating-container span: Styles the individual star spans.
  • .star-rating-container span.active: Styles the active stars (the stars that are currently selected).
  • .star-rating-container span:hover: Styles the stars on hover.

Now, modify the StarRating.js file to use this CSS:


// src/StarRating.js
import React, { useState } from 'react';
import './StarRating.css'; // Import the CSS file

function StarRating({ rating: initialRating = 0, readOnly = false, onRatingChange }) {
    const [rating, setRating] = useState(initialRating);
    const [hoverRating, setHoverRating] = useState(0);
    const totalStars = 5;

    const handleStarClick = (index) => {
        if (!readOnly) {
            setRating(index + 1);
            if (onRatingChange) {
                onRatingChange(index + 1);
            }
        }
    };

    return (
        <div className="star-rating-container">
            {Array.from({ length: totalStars }, (_, index) => (
                <span
                    key={index}
                    className={index < (hoverRating || rating) ? 'active' : ''}
                    onClick={() => handleStarClick(index)}
                    onMouseEnter={() => !readOnly && setHoverRating(index + 1)}
                    onMouseLeave={() => !readOnly && setHoverRating(0)}
                >
                    ★
                </span>
            ))}
        </div>
    );
}

export default StarRating;

Here’s what changed:

  • We imported the StarRating.css file.
  • We added the class name star-rating-container to the main div.
  • We replaced the inline styles with conditional class names.

Common Mistakes and Troubleshooting

Here are some common mistakes and how to fix them:

  • Incorrect import paths: Double-check that your import paths for StarRating.js and StarRating.css are correct.
  • Missing keys in the map function: React requires a unique key prop for each element in a list rendered using map. Make sure each star has a unique key.
  • Incorrect state updates: Ensure you’re updating the state correctly using setRating and setHoverRating.
  • CSS not applying: Make sure you’ve imported the CSS file into your component. Also, check for any CSS conflicts in your project.
  • Read-only mode not working: Verify that you’re passing the readOnly prop correctly.
  • Hover effects not working: Ensure the onMouseEnter and onMouseLeave events are correctly attached and the hoverRating state is being updated.

Key Takeaways

  • Component Structure: Understanding how to break down a component into smaller, manageable parts.
  • State Management: Using useState to manage the component’s internal state.
  • Event Handling: Handling user interactions like clicks and mouse events.
  • Conditional Rendering: Rendering different content based on the component’s state or props.
  • CSS Styling: Applying styles to the component using CSS classes.
  • Props: Passing data and configuration options to the component.

FAQ

Q: How can I customize the number of stars?

A: You can easily customize the number of stars by changing the totalStars variable in the StarRating component.

Q: How can I change the star icon?

A: You can replace the Unicode star character (★) with any other icon or image. If you use an image, you’ll need to use an <img> tag and adjust the styling accordingly.

Q: How do I handle the rating value in the parent component?

A: You can use the onRatingChange prop. Pass a function to the StarRating component that will be called whenever the rating changes. This function will receive the new rating value as an argument.

Q: How can I add a reset button?

A: You can add a button that calls setRating(0) to reset the rating to zero. This button should be placed within the parent component that uses the StarRating component.

Q: How can I style the stars differently based on the rating value?

A: You can add conditional CSS classes to the star elements based on the rating value. For example, you could add different colors or sizes to the stars based on the rating.

Creating a star rating component is a fundamental task, offering a practical introduction to React development. You’ve learned how to create a reusable component, handle user interactions, and manage state effectively. The techniques demonstrated in this tutorial, from setting up the project to incorporating dynamic styling, provide a solid foundation for building more complex React applications. Consider expanding this component by adding features like persistence with local storage, integrating it with a backend to store user ratings, or allowing users to submit reviews alongside their rating. The possibilities are endless, and with each feature you add, you’ll deepen your understanding of React and its capabilities. The ability to create interactive and user-friendly components is a key skill in web development, and this star rating component is a great first step towards that goal. Keep practicing, experimenting, and exploring the vast world of React, and you’ll find yourself building amazing web applications in no time.