DEV Community

Angie Jones
Angie Jones

Posted on

Using Slice for Star Rating Effect

I have a rating system where users can rate items from 1 to 5. I used Font Awesome to display 5 unfilled stars.

5 unfilled stars

<div id="stars">
    <i class="fa-2x far fa-star gold-text" onclick="vote(1)"></i>
    <i class="fa-2x far fa-star gold-text" onclick="vote(2)"></i>
    <i class="fa-2x far fa-star gold-text" onclick="vote(3)"></i>
    <i class="fa-2x far fa-star gold-text" onclick="vote(4)"></i>
    <i class="fa-2x far fa-star gold-text" onclick="vote(5)"></i>
</div>
Enter fullscreen mode Exit fullscreen mode

When a user clicks on one of the stars, I'd like to add some sort of effect. I'm a bit too lazy to fight with CSS today in order to implement some cool animation, so instead I'm just going to use JavaScript to display an effect.

5 stars. Stars 1, 2, and 3 are filled. Stars 4 and 5 are unfilled

Inside of the vote() function, I get an array of all of the star elements, and I want to fill in all of the stars... up to the one the user clicked.

To do this, I chose to use the slice function. slice allows you to capture a subset of the array to further work on, which is perfect in my case because unless they choose a 5-star rating, I only need to fill in a subset of the stars.

slice allows you to specify what should be the first element of the sub-array, and optionally where the slicing should end (this ending index is not inclusive so is not a part of the new array. The element right before this index will be the last element of the resulting array).

Let's say the user wants to leave 3 stars. That means, I need to fill in the 1st, 2nd, and 3rd stars. So, my arguments would be 0 and 3, meaning begin the slice at the first element of the array, and stop when you get to index 3 (note that index 3 would be the 4th star and we don't want this included).

Once I have this sliced array, I can further operate on it.

To fill in the stars, I changed the Font Awesome class for each star in my sliced subset from far to fas (the solid option of this icon).

function vote(rating) {
    $('#stars i')
        .slice(0, rating)
        .each(function(){
            $(this).toggleClass('far fas')
        })
}
Enter fullscreen mode Exit fullscreen mode

And voila!

Animated image demonstrating clicking the 3rd star and stars 1, 2, and 3 go from unfilled to solid

Would you have done something differently? Feel free to share you ideas in the comments!

Top comments (4)

Collapse
 
ashleyjsheridan profile image
Ashley Sheridan

It would be more accessible to build the stars as a series of radio buttons. You would automatically gain keyboard functionality and it would present to screen readers as a more suitable control type.

I did something like this a while back github.com/AshleyJSheridan/accessi...

Collapse
 
techgirl1908 profile image
Angie Jones

thanks for this tip!

Collapse
 
link2twenty profile image
Andrew Bone

I look forward to the day we have :has() in CSS so we can do something like this.

Collapse
 
merri profile image
Vesa Piittinen • Edited

Here is what you can do now in the sense of no JavaScript + minimalistic CSS + maintain accessibility.

Biggest advantage here is the super tiny CSS to achieve all the features. The greatest downside is that arrow controls work in reverse of expectation, you could change that with JavaScript if you want to maintain a minimalistic CSS (or by using :has instead and restoring elements to the correct order).