A Really Simple Star Rating Input in React

One of our current projects has come with a few interesting UI designs, some can turn out to be quite complex but this was possibly one of the simplest yet. Looking online there are a few packages that can do this but it soon became clear that it might be much quicker to just write a lightweight component to do just what was needed.

rendered_start_rating.png

tl;dr here’s the gist for the Star Rating React Component on Github …or you can play about with the Star Rating React Component on CodePen

Now, this could be expanded in lots of ways but this star rating component needed to fit the following specification;

  • The stars should toggle on or off when clicked
    • We’re not interested in half-star ratings…
  • The stars should fill up as you hover over them
  • The stars should use the defined theme colours

That last requirement meant that the component used the themeContext to allow the colour to be set by the rest of the application; however for simplicity here, the color style is applied inline. Of course, it could also be passed in as a prop.

The Constructor

State for this component is pretty straight forward, it keeps a track of the rating and where the user is hovering in order to render the stars correctly. The whole component may even be possible as a function using react hooks.

The stars themselves are just Unicode characters, you could make them anything you like (the empty 🖤 and full heart ❤️ emojis for example).

hearts

The score can be provided as a prop called outOf otherwise it defaults to 5 and is used to build up an int array to map later in our the render function.

    constructor(props) {
        super(props);

        this.state = {
            stars: [],
            rating: 0,
            hovered: 0,
            selectedIcon: "★",
            deselectedIcon: "☆"
        };

        let outOf = props.outOf ? props.outOf : 5;

        for (var i = 0; i < outOf; i++) {
            this.state.stars.push(i + 1);
        }
    }

Change Rating and Hover Rating

Next we need a couple of functions When a star is clicked, we set the rating in state and we look for an onChange prop to pass the new rating to. Additionally, because we want the icon to change when we are hovering over the star, we also set the rating that is currently being hovered over.

changeRating(newRating) {
        this.setState({
            rating: newRating
        });

        if (this.props.onChange)
            this.props.onChange(newRating);
    }

    hoverRating(rating) {
        this.setState({
            hovered: rating
        });
    }

Render

Finally, in the render function, we use a div wrapper to apply some inline styling. In our application, we use themeContext to set the sizing and colours however here we just specify the fontSize and color. Inside this, we map the stars array we built in our constructor to render a span element for each star. The onClick calls our changeRating function passing in the number of the star. The onMouseEnter and onMouseLeave props simply toggle the hoverRating function.

Lastly, using some conditional statements we can check if the rating and the currently hovered rating to decide whether to show the filled or empty icon for each star in the array.

    render() {

        const { stars, rating, hovered, 
                deselectedIcon, selectedIcon } = this.state;

        return (
{stars.map(star => { return ( { this.changeRating(star); }} onMouseEnter={() => { this.hoverRating(star); }} onMouseLeave={() => { this.hoverRating(0); }} > {rating ); })}

</div> ); }

And that’s everything you need!

Like I said, this does the job but it is by no means the most comprehensive option; if you need more options you could expand on this or look at something like react-rating which does handle things like half-star ratings out of the box.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: