A Simple JavaScript Technique For Filling Star Ratings

In this short tutorial, we’ll describe a simple, yet useful method for filling star ratings using HTML, CSS and JavaScript. Here’s what we’re going to build:

A Simple JavaScript Technique For Filling Star Ratings

Grabbing the Star Icons

For our example, we’ll need the following two star icons:

A Simple JavaScript Technique For Filling Star Ratings

With that in mind, let’s first include the popular Font Awesome library in our project:

A Simple JavaScript Technique For Filling Star Ratings

The Markup

With regards to the markup, we need a table with six rows.The first row contains the table headers th, while the other five rows carry hotel details. Obviously, in your own projects, these rows might represent something different.

Here’s the required HTML:

<table>
 <thead>
    <tr>
      <th>Hotel</th>
      <th>Rating</th>
    </tr>
  </thead>
  <tbody>
    <tr class="hotel-a">
      <td>Hotel A</td>
      <td>
        <div class="stars-outer">
          <div class="stars-inner"></div>
        </div>
      </td>
    </tr>
    <tr class="hotel-b">
      <td>Hotel B</td>
      <td>
        <div class="stars-outer">
          <div class="stars-inner"></div>
        </div>
      </td>
    </tr>

    <!-- 3 more rows here -->
    
  </tbody>
</table>

Most importantly, notice the markup which is included in the second td of each row:

<div class="stars-outer"
  <div class="stars-inner"></div>
</div>

This is the markup we have to style in order to visualize the star ratings of our hotels.

So far, our project looks like this:

The CSS

At this point, let’s add some basic CSS to the table, like so:

table {
  margin: 0 auto;
  text-align: center;
  border-collapse: collapse;
  border: 1px solid #d4d4d4;
  font-size: 20px;
  background: #fff;
}

table th, 
table tr:nth-child(2n+2) {
  background: #e7e7e7;
}
 
table th, 
table td {
  padding: 20px 50px;
}
 
table th {
  border-bottom: 1px solid #d4d4d4;
}     

The next and most important step is to define the styles for the .stars-outer and .stars-inner elements. Here’s the necessary CSS:

.stars-outer {
  display: inline-block;
  position: relative;
  font-family: FontAwesome;
}

.stars-outer::before {
  content: "f006 f006 f006 f006 f006";
}

.stars-inner {
  position: absolute;
  top: 0;
  left: 0;
  white-space: nowrap;
  overflow: hidden;
  width: 0;
}

.stars-inner::before {
  content: "f005 f005 f005 f005 f005";
  color: #f8ce0b;
}

Let’s go over a few things at this point.

We load the desired Font Awesome icons through CSS. This is a two-step process. First, we apply font-family: FontAwesome to the top parent element (i.e. .stars-outer). Next, we add the icons to the target pseudo-elements by setting their unicode characters.

Here’s the unicode for the first icon:

A Simple JavaScript Technique For Filling Star Ratings

And here’s the unicode for the second one:

A Simple JavaScript Technique For Filling Star Ratings

Another thing to note is that each of our icons should appear five times inside a table row. For this reason, we lay them out like this:

.stars-outer::before {
  content: "f006 f006 f006 f006 f006";
}

.stars-inner::before {
  content: "f005 f005 f005 f005 f005";
}

With the CSS in place, the project looks as follows:

Empty Stars

You’ll have noticed that only the first icon appears. But why? It’s because earlier we defined this CSS rule:

.stars-inner {
  width: 0;
}

By removing that rule the second icon will appear on top of the first one, like this:

A Simple JavaScript Technique For Filling Star Ratings

And if we were to make the .stars-inner elements 50% wide, we’d reveal half of them:

A Simple JavaScript Technique For Filling Star Ratings

Anyhow, initially the width of the .stars-inner element should be 0 and we’ll dynamically update it depending on the rating value of the relevant hotel. Let’s see how that happens in the next section.

The JavaScript

Let’s assume that our hotels have the following rating values:

const ratings = {
  hotel_a : 2.8,
  hotel_b : 3.3,
  hotel_c : 1.9,
  hotel_d : 4.3,
  hotel_e : 4.74
};

Keep in mind that, for the sake of simplicity, we specify the aforementioned hard-coded values (between 0 and 5). In a real project though, these might be retrieved through an AJAX request. Plus, in the real world, we should do some checks to ensure the derived values are within the 0 – 5 range.

So now that we have the ratings, we perform the following actions:

  1. We loop through the ratings object. Notice that the name of each object key matches the class name of a table row. In this way, we can link an object key to a hotel.
  2. For each object key, we grab its value and convert it into a percentage value.
  3. We round the aforementioned value to the nearest 10. That means, the resulting value will be 0%, 10%, 20%, 30%, etc. This is important because it allows us to create neat half stars. For instance, a value of 50% denotes that two and a half stars are filled.
  4. We set the width of the target .stars-inner element equal to the rounded value.

Based on what we’ve described above, here’s the associated code:

const starTotal = 5;

for(const rating in ratings) {  
  // 2
  const starPercentage = (ratings[rating] / starTotal) * 100;
  // 3
  const starPercentageRounded = `${(Math.round(starPercentage / 10) * 10)}%`;
  // 4
  document.querySelector(`.${rating} .stars-inner`).style.width = starPercentageRounded; 
}

The final version of our project is the following:

Browser Support

This demo has been tested on various devices and it works well. However, if you encounter any issues, let me know in the comments below. Additionally, as you’ve possibly noticed, we use Babel to compile our ES6 code down to ES5.

Conclusion

In this short tutorial, we covered a method for filling star ratings. Hopefully, you’ve enjoyed working towards the final result–you might even take advantage of this technique in an upcoming project, or improve on it for your own needs.

As always, if you have any questions, share them with us in the comments below!