MooTools Star Ratings with MooStarRating

By  on  
MooTools Star Rating

I've said it over and over but I'll say it again:  JavaScript's main role in web applications is to enhance otherwise boring, static functionality provided by the browser.  One perfect example of this is the Javascript/AJAX-powered star rating systems that have become popular over the past five years.  Star rating systems are attractive, allow us to avoid ugly forms, and prevent unnecessary page reloads.  A new plugin by Lorenzo Stanco called MooStarRating has hit the MooTools Forge and I wanted to share with you how to use it.

The HTML

The star rating system uses an HTML form with radio buttons as the base:

<form name="ratingsForm">
    <label>Do you like this post?</label>
    <input type="radio" name="rating" value="0.5">
    <input type="radio" name="rating" value="1.0">
    <input type="radio" name="rating" value="1.5">
    <input type="radio" name="rating" value="2.0">
    <input type="radio" name="rating" value="2.5">
    <input type="radio" name="rating" value="3.0">
    <input type="radio" name="rating" value="3.5">
    <input type="radio" name="rating" value="4.0">
    <input type="radio" name="rating" value="4.5">
    <input type="radio" name="rating" value="5.0">
    <input type="radio" name="rating" value="5.5">
    <input type="radio" name="rating" value="6.0">
    <input type="radio" name="rating" value="6.5">
    <input type="radio" name="rating" value="7.0" checked="checked">
    <input type="radio" name="rating" value="7.5">
    <input type="radio" name="rating" value="8.0">
    <input type="radio" name="rating" value="8.5">
    <input type="radio" name="rating" value="9.0">
    <input type="radio" name="rating" value="9.5">
    <input type="radio" name="rating" value="10.0">
	<span id="htmlTip"></span>
</form>

Note the ID of the form and the name of the radio buttons -- we'll use those when creating our MooStarRating instance.  Also note that I'm creating "half" rating options, as well as using checked to note what the current average rating is.

The CSS

This plugin requires no additional CSS.  That's a bonus as it's one less server request.

The MooTools JavaScript

The first step in using MooStarRating is defining the image paths for the stars:

// Configure the image paths
var MooStarRatingImages = {
	defaultImageFolder: "/js/mooStarRating/images",
	defaultImageEmpty:  "empty.png",
	defaultImageFull:   "full.png",
	defaultImageHover:  "hover.png"
};

Once the path and image names are defined, it's time to create an instance of MooStarRating:

// A fake post ID for the sake of submission
var postId = 10;

// When the DOM is ready....
window.addEvent("domready",function() {	
	// Create our instance
	var starRater = new MooStarRating({
		form: "ratingsForm",
		radios: "rating",
		half: true,
		//imageEmpty: "star_boxed_empty.png", // For setting special images
		//imageFull:  "star_boxed_full.png",
		//imageHover: "star_boxed_hover.png", 
		width: 17, 
		tip: "Rate as <i>[VALUE] / 10.0</i>", 
		tipTarget: document.byId("htmlTip"),
		tipTargetType: "html"
	});
	
	// Listen for star clicks
	starRater.addEvent("click",function(value) {
		// Send ajax request to server
		new Request.send({
			url: "rating.php",
			data: { rating: value, postId: postId }
		});
	});
});

MooStarRating is loaded with options.  Here we pass the form ID and the name we provided to the radio buttons.  As I'm allowing half-stars, the half option is set to true.  MooStarRating also provides a "tip" functionality which allows a message to be displayed along side the star rating. Lastly, the click event provides the user's rating for which you may send an AJAX request to the server to save the rating. Simple!

That's it!  I love this plugin because it's simple and effective.  Big props go to Lorenzo Stanco for his excellent piece of work.  If there's enough interest, I'll create a tutorial that includes enough PHP and MySQL to get this rating system working with real data.

Recent Features

  • By
    Facebook Open Graph META Tags

    It's no secret that Facebook has become a major traffic driver for all types of websites.  Nowadays even large corporations steer consumers toward their Facebook pages instead of the corporate websites directly.  And of course there are Facebook "Like" and "Recommend" widgets on every website.  One...

  • By
    Designing for Simplicity

    Before we get started, it's worth me spending a brief moment introducing myself to you. My name is Mark (or @integralist if Twitter happens to be your communication tool of choice) and I currently work for BBC News in London England as a principal engineer/tech...

Incredible Demos

  • By
    Spoiler Prevention with CSS Filters

    No one likes a spoiler.  Whether it be an image from an upcoming film or the result of a football match you DVR'd, sometimes you just don't want to know.  As a possible provider of spoiler content, some sites may choose to warn users ahead...

  • By
    HTML5 Context Menus

    One of the hidden gems within the HTML5 spec is context menus. The HTML5 context menu spec allows developers to create custom context menus for given blocks within simple menu and menuitem elements. The menu information lives right within the page so...

Discussion

  1. Eric C.

    Simple idea, great execution!

  2. I’ve actually been looking for a good rating plugin for my new application. Might have to switch over to MooTools for this project.

  3. Thorsten

    Yes, the mySQL tut also please :) !!! With preveting double votes :)

    • Yeah, I’ll create a post with the MySQL/PHP.

    • Carisa

      I didn’t find it in earlier posts. Did you already made it?

  4. Matthew F

    If you wanted to make an accessible version of this, it would seem that you should a) make the links reachable by keyboard, b) listen for the focus event.

    • Matthew F.

      My quick attempt to add accessible features, for screen reader and keyboard only users:

      var AccessibleMooStarRating = new Class({
      	Extends: MooStarRating,
      	initialize: function(options) 
      		{
      		// Run the parent class's initialization
      		this.parent(options);
      
      		// Default value for 'text' option
      		Object.append(this.options,
      			{
      			text: "[VALUE] of 10"
      			});
      
      		var me = this;
      		this.stars.each(function(star)
      			{
      			star.set({
      				// Needs an href to be reachable by keyboard
      				href: "#",
      				// Set the link text to something semantically valid
      				text: me.options.text.replace('[VALUE]', star.retrieve("ratingIndex")),
      				// Hide the text for visual users
      				styles: {
      					"text-indent": (me.options.width + 10) + "px",
      					"overflow": "hidden",
      					},
      				// Add keyboard equivalents for mouse actions
      				events: {
      					'keyup': function(e) {
      						if(e.key == "enter" || e.key == "space")
      							{
      							me.setCurrentIndex(this.retrieve('ratingIndex'));
      							me.fireEvent('click', me.getValue());
      							}
      						},
      					'focus': function() { me.starEnter(this.retrieve('ratingIndex')); },
      					'blur': function() { me.starLeave(); },
      					}
      				});
      			});
      		}
      	});
      

      (Sorry for the Whitesmith’s indentation style, I know many find it hard to read)

    • Matthew F.

      And now I learn that any code blocks separated by an empty line get broken into separate blocks. Sorry about that as well, it should all be one block!

  5. This is really beautiful. MooTools is a real FTW library!
    I hope people will use this script and contribute to it at github.

  6. Lorenzo S.

    What an honour, David! :)

    • It’s an honor to feature it — great work Lorenzo!

  7. Unfortunately there is one big issues with this script – like with most available online – it completely breaks without JavaScript turned on. You just see a bunch of radio buttons, no images. There is now way to submit it without JavaScript. And lastly the indication of what the current rating is doesn’t work very well without JS turned on.

    This is not progressive enhancement and should, this way, only be used in a context where either Javascript is guaranteed or the application relies on JavaScript anyways.

    My approach, which I’ve written as a Joomla plug-in, works by adding a button for each star. The design is provided with a stylesheet. This works completely good without JavaScript, scripting is only used for the AJAX part and too enhance the hover effect in ways no possible with CSS.

    BTW, the same is true of your comment form as I just discovered ;)

    • Having JS generate the form would be an accessibility killer.

    • Matthew F.

      Fortunately that hasn’t been true for a long time. All major screen readers support javascript, and are able to interact with changes made to the DOM structure. As long as it appears in tab order, it will be perceived by a screen reader. The best tip I ever got regarding accessible AJAX: View a page in Firefox cursor mode and imagine you can only see the word or element that the cursor is on. If you can still use the application, the DOM changes are probably accessible. (Or something along those lines)

    • Good point about the progressive enhancement.

      I guess for JS disabled bunch of radio forms is fine, I’m just missing the Submit button that would be hidden when javascript is turned on and form action=”rating.php”. Rating.php would check if the request was made by ajax call and in case it wasn’t it would redirect back to referring page after the processing.

  8. Matthew F.

    (Last try, and I promise to never post on this blog again!)

    Good point: It would be a best-practice to either have the Javascript generate the entire form, or require HTML in the source that can be used by non-javascript users – particularly accessible code like:

    <form method="post" action="rating.php">
    <input type="hidden" name="postId" value="10" />
    <fieldset>
    <legend>Do you like this post?</legend>
    <input type="radio" name="rating" id="rating_1" value="0.5" id="><label for="rating_1">0.5 / 10</label>
    <input type="radio" name="rating" id="rating_2" value="1" id="><label for="rating_1">1 / 10</label>
    ...
    <input type="radio" name="rating" id="rating_20" value="10" id="><label for="rating_20">10 / 10</label>
    </fieldset>
    <input type="submit" value="Rate This Post"> 
    </form>
    

    You could then use Mootools’ Form.Request class to submit the form (for users with Javascript), and require rating.php to redirect back to its referrer for non-Ajax requests.

  9. kolin

    superb, bye-bye clunky ASP.NET ajax star rating. hello moo.

    thanks david

    mootools > *

  10. Mootools functionality is the best

    but what’s the idea on this percentage when some people try to rate
    and more and more users cover it……..

    how can we get all the ranks into one whole percentage

    • This should be done server side.
      PHP will help you calculate that whole percentage by taking the already submitted values from a database.

  11. Is it possible for the user to select float values (9.5 for example)?

  12. olivier

    Thanks for the tip, David.
    In the Options, consider replacing ‘click’ with a regular ‘onClick’ then it will be perfect ;)

  13. Carisa

    I’m asking about the tutorial :] Tried to replay on the post from February 8, 2011 @ 9:02 pm

  14. alex

    Hi what if i have more than 5 forms to rate how can i do it do i have to write more than 5 functions ?
    Thank you.

  15. Bjoern Willnat

    Ok, but what is about a multiple Rating?

  16. ArKey

    Safari 5.0.x does not display the stars on the left side. Only white space. The grey stars on the right are ok.

  17. bogdan

    Does it work with mootools 1.4.2? Joomla uses that version.

  18. Not bad but I prefer this 5 star rating system, it has 9 different types of stars like pumpkins, christmas, crystal, soft, darkness and more. Pretty cool.

    http://templatz.co/5-star-rating-system.php

  19. scratchdisk

    Thank you very much for this. Has anyone noticed the images are requested over and over from the server while the starts are hovered over?

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!