Creating a Custom Rating System with JavaScript
Published June 20, 2024 at 5:00 pm

Why Create a Custom Rating System with JavaScript?
Creating a custom rating system with JavaScript allows you complete control over the design and functionality of your rating components.
With a custom solution, you can tailor the appearance to match your site’s theme, include unique features, and ensure the system integrates seamlessly with your backend.
Off-the-shelf solutions may not provide the flexibility you require.
TLDR: Implementing a Custom Rating System in JavaScript
Here’s a quick example of how to create a 5-star rating system using pure JavaScript:
// Add HTML for the rating star
// Add CSS for the star rating
// JavaScript code for rating system
In this example, we create a simple 5-star rating system using plain JavaScript, HTML, and CSS.
Setting Up the HTML Structure
First, we need to set up the HTML structure for our rating system.
We'll create a div
element to hold our stars:
This div
will serve as the container for our rating stars.
We can use JavaScript to generate the stars dynamically inside this container.
Styling the Stars with CSS
Next, we'll add some CSS to style the stars so that they resemble a typical rating system.
Here's a simple CSS snippet:
The .star
class adds basic styles to the stars, such as setting the font size and changing the cursor to a pointer.
The .star.rated
class changes the color of the stars to gold when they are rated.
Using JavaScript to Add Interactivity
To add interactivity, we'll write JavaScript that dynamically generates the stars and handles the rating logic.
First, we'll use JavaScript to create 5 stars and append them to the div
:
document.addEventListener('DOMContentLoaded', () => {
const ratingDiv = document.getElementById('rating');
const stars = Array(5).fill().map((_, i) => {
const star = document.createElement('span');
star.textContent = '★';
star.classList.add('star');
ratingDiv.appendChild(star);
return star;
});
});
We use Array(5).fill().map(…
to create an array of 5 elements and generate a star for each element.
Each star is represented by a span
element with the star
class and is appended to the rating div
.
Handling User Interaction
Now, we need to handle user interactions, such as clicking on a star to set the rating.
We'll add event listeners to each star for the click
event:
stars.forEach((star, index) => {
star.addEventListener('click', () => rateStar(index + 1));
});
When a star is clicked, we call the rateStar
function, passing the index of the clicked star plus one.
The rateStar
function handles updating the rating and visually marking the rated stars:
function rateStar(rating) {
stars.forEach((star, index) => {
star.classList.toggle('rated', index < rating);
});
console.log(`User rated: ${rating} stars`);
}
This function iterates over all the stars and toggles the rated
class on the stars that are less than the current rating.
We also log the rating to the console for debugging purposes.
Ensuring Accessibility
Making your custom rating system accessible ensures that it can be used by everyone, including those with disabilities.
Here are some tips for making your rating system accessible:
- Use appropriate ARIA roles and properties.
- Provide keyboard navigation.
- Ensure color contrast.
Adding ARIA Roles
Adding ARIA roles and properties helps screen readers understand the role and state of each element.
Here's how you can enhance the accessibility of your rating system:
Star 1
Each star should have the role="radio"
and aria-checked
attributes to indicate its state:
star.setAttribute('role', 'radio');
star.setAttribute('aria-checked', 'false');
Update the rateStar
function to set the aria-checked
attribute:
function rateStar(rating) {
stars.forEach((star, index) => {
star.classList.toggle('rated', index < rating);
star.setAttribute('aria-checked', index < rating);
});
}
Providing Keyboard Navigation
Adding keyboard navigation ensures that users can interact with the rating system using the keyboard.
Handle the keydown
event on each star to support keyboard navigation:
stars.forEach(star => {
star.setAttribute('tabindex', 0);
star.addEventListener('keydown', event => {
if (event.key === 'Enter' || event.key === ' ') {
rateStar(stars.indexOf(star) + 1);
}
});
});
Ensuring Color Contrast
To ensure color contrast, choose colors that meet the WCAG standards for contrast ratio.
Use tools like the WebAIM Contrast Checker to test your color choices.
Deploying Your Custom Rating System
After creating and testing your custom rating system, you are ready to deploy it.
Ensure your system is well-documented and include instructions for integrating it into your site or application.
Common Pitfalls and How to Avoid Them
Creating a custom rating system presents some challenges. Here are common pitfalls and how to avoid them:
Overcomplicating the Design
Do not add unnecessary features that can overcomplicate the code.
Keep the design simple and intuitive.
Ignoring Accessibility
Ensure that your rating system is accessible to all users by using ARIA roles and keyboard navigation.
Lack of Testing
Test your rating system across different browsers and devices to ensure compatibility.
FAQs
How can I change the number of stars in the rating system?
You can change the number of stars by modifying the array length in the JavaScript code:
const stars = Array(10).fill().map((_, i) => {...
Can I use images instead of text for the stars?
Yes, you can replace the text content of the star span
with an image element.
How do I make the rating persistent?
Save the rating to a backend database and load it when the page is loaded.
Extending JavaScript to Save the Rating
To make the rating persistent, you'll need to save the user's rating to a backend database.
This will allow the rating to be loaded when the page is refreshed or revisited.
Using Local Storage
As a simple solution, you can use the browser's local storage to save the rating.
Here's an example of how to modify the rateStar
function to save the rating:
function rateStar(rating) {
stars.forEach((star, index) => {
star.classList.toggle('rated', index < rating);
star.setAttribute('aria-checked', index < rating);
});
localStorage.setItem('rating', rating);
console.log(`User rated: ${rating} stars`);
}
To load the stored rating when the page loads, modify the JavaScript to check for a stored rating:
document.addEventListener('DOMContentLoaded', () => {
const savedRating = localStorage.getItem('rating');
if (savedRating) {
rateStar(parseInt(savedRating));
}
});
This simple approach works well for client-side data storage but won't persist across different devices.
Saving to a Backend Database
For a more robust solution, save the rating to a backend database.
Here's a basic example using Fetch API to send the rating to a server:
function rateStar(rating) {
stars.forEach((star, index) => {
star.classList.toggle('rated', index < rating);
star.setAttribute('aria-checked', index < rating);
});
fetch('/api/save-rating', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ rating }),
}).then(response => {
if (response.ok) {
console.log(`Rating saved: ${rating} stars`);
}
});
}
The server should handle the "/api/save-rating" endpoint to save the rating to a database.
Loading the Rating from the Backend
To load the rating from the backend when the page loads, fetch the rating from the server:
document.addEventListener('DOMContentLoaded', () => {
fetch('/api/get-rating')
.then(response => response.json())
.then(data => {
if (data.rating) {
rateStar(data.rating);
}
});
});
Ensure the server responds with the stored rating in JSON format.
Handling Different States
When creating a rating system, consider how to handle different states such as hover, focus, and disabled.
Adding Hover Effect
To provide feedback as users hover over the stars, add a hover effect using JavaScript:
stars.forEach((star, index) => {
star.addEventListener('mouseenter', () => highlightStars(index + 1));
star.addEventListener('mouseleave', () => clearHighlight());
});
function highlightStars(count) {
stars.forEach((star, index) => {
star.classList.toggle('highlighted', index < count);
});
}
function clearHighlight() {
stars.forEach(star => star.classList.remove('highlighted'));
}
Update the CSS to style the .highlighted
class:
This provides immediate visual feedback when users hover over the stars.
Focusing on Accessibility
Make sure the rating system is accessible by adding focus styles:
Example CSS for focus styles:
This improves accessibility for keyboard users.
Disabling the Rating System
Sometimes, you might need to disable the rating system, perhaps when the user already rated.
Here is an approach to disable stars dynamically:
function disableRating() {
stars.forEach(star => {
star.classList.add('disabled');
star.setAttribute('tabindex', -1);
star.removeEventListener('click', rateStar);
});
}
Update the CSS to style the .disabled
class:
Call the disableRating
function when needed to disable the stars.
Optimizing Your Rating System
For better performance and user experience, optimize your rating system.
Improving Performance
When dealing with a large number of stars, performance can become an issue.
Use requestAnimationFrame for smoother interactions:
function rateStar(rating) {
requestAnimationFrame(() => {
stars.forEach((star, index) => {
star.classList.toggle('rated', index < rating);
star.setAttribute('aria-checked', index < rating);
});
localStorage.setItem('rating', rating);
console.log(`User rated: ${rating} stars`);
});
}
This ensures a smoother and more responsive user experience.
Improving UX with Animations
Adding animations can enhance the user experience.
Here's an example of animating the stars when rated:
Animations make the rating system more engaging.
Clear Button to Reset Rating
Add a clear button to allow users to reset their rating:
document.getElementById('clear-rating').addEventListener('click', () => {
stars.forEach(star => {
star.classList.remove('rated');
star.setAttribute('aria-checked', 'false');
});
localStorage.removeItem('rating');
console.log('Rating cleared');
});
This gives users flexibility to change or clear their rating.
Common Issues and How to Fix Them
Issues with Hover Effects
Hover effects may not work on touch devices.
Solution: Use focus styles to provide similar feedback for touch users.
Rating Persistence
Users might lose their rating if not implemented properly.
Solution: Always test the persistence mechanism and ensure data integrity.
Cross-browser Compatibility
The rating system might behave differently across browsers.
Solution: Test your system on multiple browsers and addresses compatibility issues.
Related Frequently Asked Questions
How can I change the number of stars in the rating system?
You can change the number of stars by modifying the array length in the JavaScript code:
const stars = Array(10).fill().map((_, i) => {...
Can I use images instead of text for the stars?
Yes, you can replace the text content of the star span
with an image element.
How do I make the rating persistent?
Save the rating to a backend database and load it when the page is loaded.
Is it possible to make the rating system accessible?
Yes, use ARIA roles, keyboard navigation, and ensure color contrast for accessibility.
How can I add animations to the rating stars?
Add CSS transitions to the .rated
class for smooth animations:
.star.rated { transition: color 0.3s ease-in-out; }
What are common issues with custom rating systems?
Common issues include hover effects not working on touch devices and rating persistence problems.
How do I test the rating system across different browsers?
Use browser testing tools and manually check the system on different browsers to ensure compatibility.
Is it possible to disable the rating system?
Yes, you can add a .disabled
class and remove event listeners to disable it:
function disableRating() { stars.forEach(star => { star.classList.add('disabled'); star.setAttribute('tabindex', -1); star.removeEventListener('click', rateStar); }); }