Spicing Up Your Website With jQuery Goodness


There comes a point in every website design when you simply want to give the website a little spice to impress the visitor and make it memorable. You want that sexy interaction to capture the user’s attention. In our previous articles, we showed you how to spice up your website with sexy buttons1, practical elements2 and attractive visual effects3.

In this article, we’ll discuss how to seduce your visitors with a little JavaScript action. In our examples, we’ll be using jQuery, a fast and concise JavaScript library that simplifies HTML document traversing, event handling, animation and Ajax interactions for rapid Web development. Ready? Let’s get things rolling!

Ajax Image Uploader

Image uploads will be much better after your read this. Guaranteed. By using a bit of jQuery, we can upload images with previews.

How do you upload images now? You select a file and click upload. Simple, right? Except that once you select your image, you can no longer see what was selected. The name of the file is at the end of the input field, and if the input field is short or the file path is deep, you won’t see anything useful. You’ll forget what you selected and have no idea what you’re about to upload.

Now try this variation on uploading an image. We ditch the “Upload” button in favor of a “Save” button and fire the Ajax upload event as soon as a file is selected. The image is processed server-side, and a thumbnail is loaded onto the existing page. Doesn’t that feel so much better? We now have a visual representation (imagine that!) of the image we selected.


This is particularly useful in larger forms where many fields will be submitted in a single action. It allows the user to review the form before pressing “Save” and see what image (or images) they selected.

How does it work? Here’s the code. You’l need jQuery and the Ajax Upload jQuery plug-in5. Link them up, and make sure jQuery is loaded first.

<script src="/js/jquery.min.js" type="text/javascript"></script>
<script src="/js/ajaxupload.js" type="text/javascript"></script>

Here is the JavaScript we will use in its entirety.


	var thumb = $('img#thumb');	

	new AjaxUpload('imageUpload', {
		action: $('form#newHotnessForm').attr('action'),
		name: 'image',
		onSubmit: function(file, extension) {
		onComplete: function(file, response) {
			thumb.attr('src', response);

Let’s break the code down now and look at what’s really going on. First, we attach the AjaxUpload behavior to our file form element.

new AjaxUpload('imageUpload', {

Next, we specify where to post the Ajax upload. We want to keep all of our URLs in our HTML document, so we pass this URL using the action attribute of our form element.

action: $('form#newHotnessForm').attr('action'),

Set the name of the file form element that will be posted to your server.

name: 'image',

Add a class to your preview div to indicate that the image is uploading. In our case, we are applying a background image to the preview div. We also need to set the image tag to display: none; in the preview div, so that the loading background image is visible, as well as for a more subtle reason explained below.

onSubmit: function(file, extension) {

When the image has been uploaded, we have to do two things:

  • First, we have to set the src attribute of our preview img tag to the new thumb.
  • Secondly, we have to remove the loading class. If we simply execute these things in that order, then we would see an annoying flicker of the old image when the loading class has been removed but the new image has not yet loaded.

We avoid the annoying flicker of the old image by waiting to remove the loading class until after the preview image’s load event fires. We also unbind our listener after it has fired because we want to capture this event only once.

onComplete: function(file, response) {

Lastly, we set the source of the preview image to the thumbnail that our server has just created. In this example, the response from the Ajax call is just the thumbnail’s URL as text. You could return it in whatever fancy format you like.

thumb.attr('src', response);

If JavaScript-support is disabled in user’s browsers, they will get the good old submit form without the interactive preview. Clean and functional solution, with rich interactions for users with more capable browsers.


Better Image Uploads7

Want to try out and implement the image uploader yourself? Check out a live demo, the example code and more for this improved way to support image uploads on your website.

Check out the live demo »8

Validation With jQuery Text-Change Event

Here’s a pretty common problem: you have a text form to validate client-side. Doing this is easy enough when the form is submitted, but in some cases doing it as the user is typing is best. For example, imagine how annoying Twitter9 would be if you had to submit your tweet before you were told how many characters it was.

Keep in mind, though, that this kind of immediate validation can be overused or abused. Don’t insult the user by congratulating them for every piece of text they enter in a field.


Implementing this requires that you bind events to the keyup event — and a couple other events if you want to detect text changes on cut-and-paste events. Even if you’re a JavaScript god, having to keep writing this logic over and over again is tedious. We created a text-change event plug-in to help you handle all text-change events.

Detecting the Text (Better Than Twitter)

We begin by detecting text in the standard textarea. Look at the shot below: looks like a standard textarea with a disabled “Save” button.


If you add text to the field, then the “Save” button enables and then disables when no text is in the field. Moderately impressive, right?


Now, what if you try copying, pasting or cutting text with the shortcut keys? That works as well. What about right-clicking or using the “Edit” menu? Works, too. (By the way, Twitter doesn’t support the click or menu interactions.)

The code behind this is pretty simple. You’ll need to download and link up the textchange plug-in13.

<script src="/javascripts/plugins/jquery.textchange.js"></script>

The plug-in adds the hastext and notext events, to which you can bind input and textarea elements.

$('#exhibita').bind('hastext', function () {
  $('#exhibitaButton').removeClass('disabled').attr('disabled', false);
$('#exhibita').bind('notext', function () {
  $('#exhibitaButton').addClass('disabled').attr('disabled', true);

The hastext event fires when the element goes from having no text to having text, and the notext event fires when the element goes from having text to being blank. Looking for more advanced validation? Keep reading.

Detecting Text Change

What about detecting text change in the field?


This is very easy, too. A third textchange event fires whenever the text changes, and it provides you with the previous value.

$('#exhibitb').bind('textchange', function (event, previousText) {

Text changed from <strong>' + previousText + '</strong> to <strong>' + $(this).val() + '</strong> </p>'); });

Twitter-Style Validation


We can implement some simple Twitter-like validation with just a single line and our textchange event.

$('#twitter').bind('textchange', function (event, previousText) {
  $('#charactersLeft').html( 140 - parseInt($(this).val().length) );

Ajax Save


With a little more code and setTimeout, we can hook up an Ajax call to save a few seconds once the user stops editing. The Ajax call is just stubbed out here, but you get the idea.

var timeout;
$('#ajaxSave').bind('textchange', function () {
    var self = this;
    timeout = setTimeout(function () {
    $('#ajaxFired').html('Saved: ' + $(self).val());
  }, 1000);

Validate Text


This may sound contrived, but say you would like to ensure that the two words “companion cube18” are in the emergency intelligence incinerator (i.e. the text field) before allowing the user to continue. No problem:

$('#emergencyIntelligenceIncinerator').bind('textchange', function () {
  if ($(this).val().indexOf('companion cube') !== -1) {
    $('#continue').removeClass('disabled').attr('disabled', false);

jQuery Text-Change event can be very useful for web applications that are aiming for a high level of interactivity and visual feedback. You may even want to analyze some of the input and provide helpful clues. For instance, if the user is opening a new ticket in your support area, you may want to present links to possibly related answers in the support forum. Be sure not to analyze every keystroke, though, as it could result in a significant overhead for the back-end. And it is also important to keep in mind that the immediacy of the application should be subtle and should not interrupt user’s interaction.


Text Change Events20

Don’t fret about complicated validation, text events and edge cases. Check out the live demo and download the plug-in, which makes it a snap to perform a number of functions on text boxes to look for values, changes and more.

Check out the live demo »21

JavaScript Annotation Plug-In


An application that we recently developed (Notable23) allows users to collect user feedback through interactive tools. Most of these tools require the user to annotate an image. We figured that many folks are trying to solve the same problem, so why not create a plug-in that they can use? This is the result. Our plug-in uses jQuery and makes it very simple to add and save image annotations.

To start off, download the JS Annotation Plug-In24. To use the plug-in, just link up jQuery (1.2.3 or higher) and our plug-in.

<script src="/javascripts/plugins/jquery.js"></script>
<script src="/javascripts/plugins/jquery.annotate.js"></script>

Meet Nutmeg the Dog. After clicking on a random spot on Nutmeg, you’ll see the black circle appear.


function blackNote() {
  return $(document.createElement('span')).addClass('black circle note')

Here’s how it works: The first parameter to annotatableImage is a function that is implemented by you and that defines the element to be added when you click. In the example above, that function is called blackNote. Simple, right?

How to Save the Annotations?

Glad you asked. Use the jQuery selector to grab all the elements that you want to serialize, and call the serializeAnnotations function.

$('#nutmeg span.note').serializeAnnotations();

These values are returned in an array of objects, so you can easily save them with an Ajax call. The response_time variable is the time in milliseconds that the user took to add the annotation after you made the call to annotatableImage.


Let’s Get Relative

In our website feedback tool we needed to show our annotations in different-sized versions of our original image. The full size is just won’t always cut it in the world of good design. To make this easier, we store the x and y positions of our annotations relative to the width and height of the image.


If you didn’t pass fifth-grade math, don’t worry: our plug-in does all the basic arithmetic for you. Warning: if you change the aspect ratio or crop the image, this will not work properly. Also, be sure to always store x and y as floating-point data types.

$('#smallNutmeg').addAnnotations(blackNote, annotations);

The annotations variable is an array of objects with x and y attributes. It looks exactly like the array returned by the serializeAnnotations function without the response_time attribute. What other attributes might you put in the annotation object? Read on…

Passing Attributes

We may want to pass some data to each of our annotations when adding existing annotations. Maybe we have numbered our annotations, or have added special classes or behaviors, whatever.


The function we pass to annotatableImage accepts a single parameter, which is the annotation object from the array that you passed to addAnnotations. In this example, we added a position attribute, which we will display.

  return $(document.createElement('span')).
    addClass('black circle note').html(annotation.position);
    {x: 0.3875, y: 0.3246, position: 4}, 
    {x: 0.57, y: 0.329, position: 2}

Hitting All the Positions

When we were annotating Nutmeg, you may have noticed that the annotation was centered at your click position. This may be great for circles and sparkly unicorns, but sometimes we may want to position our annotations differently.

The xPosition and yPosition options allow you to indicate where the annotation is positioned relative to the click. Options are middle (default), left, right and middle (default), top, bottom, respectively.

  return $(document.createElement('span')).addClass('set-label');
}, {xPosition: 'left'});

Give Nutmeg some clicks on our demo page to see what we’re talking about. In this example, we are positioning the click on the left side of the annotation.

Warning: make sure to pass the xPosition and yPosition to the serializeAnnotations function if you set these options in annotatableImage. The default behavior is to calculate the x and y values from the middle of the annotation.


JavaScript Annotations Plug-In30

Start supporting powerful, easily implemented annotations on your website or app with this plug-in. Adding notes, descriptions and more to these annotations is simple.

Check out the live demo »31

Bonus: CSS Grid Builder


In our design process, we have been using a flexible grid framework that lets us rapidly prototype and implement websites. Recently, we’ve created some variant grids for different widths and gutter sizes, so we thought, why not just create grids on the fly with a simple tool?

Please feel free to use the ZURB CSS Grid Builder33 to build and generate source code for a simple, flexible grid framework for variable grid sizes and column numbers. Play around with it — we prefer it to a more full-featured solution such as YUI because it’s lighter and a little more flexible.


CSS Grid Builder35

Check out the CSS Grid Builder in the playground. You can preview the grid in different-sized browser windows and output a complete CSS framework.

Check out the grid builder »36



  1. 1 http://www.smashingmagazine.com/2009/12/02/pushing-your-buttons-with-practical-css3/
  2. 2 http://www.smashingmagazine.com/2009/12/16/stronger-better-faster-design-with-css3/
  3. 3 http://www.smashingmagazine.com/2010/01/25/the-new-hotness-using-css3-visual-effects/
  4. 4 http://www.zurb.com/playground/ajax_upload
  5. 5 http://valums.com/ajax-upload/
  6. 6 http://www.zurb.com/playground/ajax_upload
  7. 7 http://www.zurb.com/playground/ajax_upload
  8. 8 http://www.zurb.com/playground/ajax_upload
  9. 9 http://twitter.com
  10. 10 http://www.zurb.com/playground/jquery-text-change-custom-event
  11. 11 http://www.zurb.com/playground/jquery-text-change-custom-event
  12. 12 http://www.zurb.com/playground/jquery-text-change-custom-event
  13. 13 http://www.zurb.com/javascripts/plugins/jquery.textchange.min.js
  14. 14 http://www.zurb.com/playground/jquery-text-change-custom-event
  15. 15 http://www.zurb.com/playground/jquery-text-change-custom-event
  16. 16 http://www.zurb.com/playground/jquery-text-change-custom-event
  17. 17 http://www.zurb.com/playground/jquery-text-change-custom-event
  18. 18 http://en.wikipedia.org/wiki/Portal_(video_game)
  19. 19 http://www.zurb.com/playground/jquery-text-change-custom-event
  20. 20 http://www.zurb.com/playground/jquery-text-change-custom-event
  21. 21 http://www.zurb.com/playground/jquery-text-change-custom-event
  22. 22 http://www.zurb.com/playground/javascript-annotation-plugin
  23. 23 http://www.notableapp.com
  24. 24 http://www.zurb.com/javascripts/plugins/jquery.annotate.js
  25. 25 http://www.zurb.com/playground/javascript-annotation-plugin
  26. 26 http://www.zurb.com/playground/javascript-annotation-plugin
  27. 27 http://www.zurb.com/playground/javascript-annotation-plugin
  28. 28 http://www.zurb.com/playground/javascript-annotation-plugin
  29. 29 http://www.zurb.com/playground/javascript-annotation-plugin
  30. 30 http://www.zurb.com/playground/javascript-annotation-plugin
  31. 31 http://www.zurb.com/playground/javascript-annotation-plugin
  32. 32 http://www.zurb.com/playground/css-grid-builder
  33. 33 http://www.zurb.com/playground/css-grid-builder
  34. 34 http://www.zurb.com/playground/css-grid-builder
  35. 35 http://www.zurb.com/playground/css-grid-builder
  36. 36 http://www.zurb.com/playground/css-grid-builder

↑ Back to top Tweet itShare on Facebook

ZURB is a close-knit team of interaction designers and strategists that help companies design better products & services through consulting, products, education, books, training and events. Since 1998 ZURB has helped over 75+ clients including: Facebook, eBay, NYSE, Yahoo, Zazzle, Playlist, Britney Spears, among others.

  1. 1

    As a Mac user, I am used to just drag files onto the “choose file” button. But in this example, this is not possible. Although pretty much better than the old and busted one.

  2. 2

    This is why I freaking love Smashing Magazine! You guys offer the best tutorials and real world examples. I used a lot of what I learned in shaping the front end to my API site at http://theeasyapi.com. It’s a free service that lets other developers access API’s easily. I tried to make the interface as simple as possible so other developers can use the service. Great job ZURB providing examples that make sense and almost anyone can follow.

  3. 3

    Such an awesome article. Love the little bits like the companion cube part, and some great inspiration with the captions and things. Awesome!

  4. 4

    Wow really nice tutorial hats of to you Zurb keep up the great work brilliant guide must say.


  5. 5

    Good read! I am so happy to see JQ taking that infamous turn from being a code based phenomena to it being integrated in easy to handle, almost code free kits and plug-ins. Soon enough everyone will be doing it and then, after 10 years (give or take) we will throw it out the window and replace it with something better. As I mentioned, so glad to be one step closer to that moment.

  6. 6

    Yes, jQuery is absolutely brilliant and you can do A LOT with it. And the best: coding is really fast and the results are “cross-browser-able”.

    For jQuery in real-life check here: http://www.idonext.com – it’s a web service for task & group management which uses jQuery heavily and feels like a real desktop app.

  7. 7

    JavaScript and especially jQuery is a really easy way to get interaction on websites, as shown by the following (small) showcase of international websites!

  8. 8

    There are some nice examples here for adding jQuery to your website, and some of these examples will definitely create enhanced interaction with your website.

    Then again I feel that you clearly ran out of ideas after all of the textchange parts, most notably because the annotate idea is so very specific. What about things like overlays (preventing opening new windows/tabs or changing the page)? How about lightboxes, enabling the user to stay on the page whilst viewing a larger version of an image? These seemed like obvious enhancements.

  9. 9

    I’ve started implementing jQuery into several Websites lately that I’ve designed. This will definitely come in useful and gives some good ideas. Thanks!

  10. 10

    Great article and some useful jQuery tips. We’ve just started using jQuery on some of our websites – http://www.e-motivemedia.com/category/portfolio. Hopefully we’ll be expanding our jQuery toolkit soon!

  11. 11

    Jquery here, Jquery there…

    I LOVE Mootools!

  12. 12

    Just what I need! Nice!

  13. 13

    I’ve noticed a bug in your “textchange” special event – the setup & teardown bind/unbinds don’t match:

    setup: function () {
    a(this).bind(“keyup”, a.event.special.textchange.handler);
    a(this).bind(“cut paste input”, a.event.special.textchange.delayedHandler)
    }, teardown: function () {
    a(this).unbind(“keyup”, a.event.special.textchange.keyuphandler);
    a(this).unbind(“cut”, a.event.special.textchange.cuthandler)

    I think the teardown lines should be:
    a(this).unbind(“keyup”, a.event.special.textchange.handler);
    a(this).unbind(“cut paste input”, a.event.special.textchange.delayedHandler)

    You could also improve your code by using namespaced events (http://docs.jquery.com/Namespaced_Events) to do the same with less code:

    setup: function () {
    a(this).bind(“keyup.hastext”, a.event.special.textchange.handler);
    a(this).bind(“cut.hastext paste.hastext input.hastext”, a.event.special.textchange.delayedHandler);
    }, teardown: function () {

  14. 14

    pretty fine site. comes in handy

  15. 15

    Great post!
    This is the content I like to see :)

  16. 16

    that’s very goood

    Thanks a lot

  17. 17

    I’ve found so many of your articles interesting, but most entirely from outside sources. While I understand the value of including those sources and pooling ideas and techniques, I have been building a great library of their feeds and will soon have no need to come back to SM if it continues to lack any relevant content of its own.

  18. 18

    Vitaly Friedman (Smashing Editorial)

    June 15, 2010 9:02 am

    Interesting, Adam. Please keep in mind that research for the techniques, tools and resources presented in our posts usually takes 15+ hours. Besides, we do publish original articles. Please just take a look around. Still, good luck. And please let us know when your library is available online.

  19. 19

    Good catch Marcus. I fixed this in the gist and the minified code on the playground page.

  20. 20

    Thanks for the tips!

    OT: rofld @ the dogs eyes. haha

  21. 21

    Thanks for the quick feedback. I’m not bashing SM and mean no disrespect. Also, I have no intention of publishing anything online in regards to my personal bookmarks. I’m simply saying that it’s easy to grab all the sources you present, subscribe to them, and bail. I recognize that you write your own articles. You also do a great job of bringing only the best outside articles to the front. So great of a job, in fact, that I’m afraid I prefer the outside articles to yours. That’s just my opinion though.

  22. 22

    This is really good info~ Thank you for sharing~~ And cute photos too :D

  23. 23

    More great content from SmashingMag!

    jQuery, along with CSS3 and HTML5, is the best thing to come along for web designers and developers in years. I know I, for one, have been enjoying implementing all sorts of useful jQuery features into my site, and I am looking forward to learning new tips and techniques to add to http://www.gillico.com and other sites I work on. I never bothered with Flash, and now, finally, something better has come along!

  24. 24

    Disabling the ‘save’ button?!
    Usability nightmare!

  25. 25

    Oh nice post !

  26. 26

    I love the eyes on the dog. That little touch of humour goes a long way.

    Great article, and valid points, and resources, presented.

  27. 27


  28. 28

    I’ve been using jQuery for sometime so have seen a lot of this before but I have to agree with Russell Bishop that given the title of the article there are a lot of common enhancements that would have been good to mention like lightbox etc.
    For those interested perhaps take a look around http://plugins.jquery.com/

  29. 29

    The Ajax Image Uploader simply doesn’t work in Chrome. I think its the Ajax Upload plugin. Also doesn’t work in Minefield either

  30. 30

    aw aw aw any bonus theres .. :P
    awesome list…thanks smashing ^_^’

  31. 31

    I like a image on Passing Attributes. So fun.

  32. 32

    This post is gold. Thanks for sharing.

  33. 33

    Awesome! But does it blend? Keep ’em coming, SM.

  34. 34

    This is most usefull…

  35. 35

    Sorry but am I the only one noticing all the unnecessary spam in many of the comments. It’s really annoying..

  36. 36

    Some very handy JQuery awesomeness. Thanks SM & Zurb!

  37. 37

    Jquery is something really important in the website industry life cycle. I am glad that wpfrompsd.co.uk company helped me in fixing my problem

  38. 38

    Thanks to everyone who wrote the article, it was a pleasure reading it. I quite liked the visual representation you made through out, particularly when describing what the code would do – it made it a lot easier to follow. The links to the live demo’s would be better if they were more noticeable – a quick scroll through didn’t make them immediately apparent…
    I really liked the information about detecting text change to change text. Something like that would be really effective within a search feature on my website katskinner.com.
    The Detect text code would be also really helpful when users are submitting comments, or more likely posts on my forums at katskinner.com/forums/. It just helps to stop blank posts (an issue I used to have with some of my coding….). Pity something like this isn’t all you need for anti-spam…

  39. 39

    Very nice list of ideas, I especially like how you have the non jQuery and with jQuery.

  40. 40

    What about the ajax upload one? It doesn’t work in Chrome or Minefield. I think its the ajax upload plugin itself maybe?

  41. 41

    Exactly what some of my websites need! Thanks for this great resource :)

  42. 42

    awesome post, will come in handy

  43. 43

    Alison Barrett

    July 1, 2010 5:27 pm

    Something you can still do is click the Browse button and then drag the file onto the browser that pops up. That way, it’s only one more click than what you’re used to. :)

  44. 44

    That’s amazing If I can do it, I think I can save a lot of money!

  45. 45

    I don’t like ajex, not good for slow net users.

  46. 46

    Parabéns ZURB Muito bom tutorial

  47. 47

    David Tennant lover Posted on First, fnatastic choice of dog breed =]Bernese’ are brilliantWell, I like the name Tess for a Bernese because, idk, just suits them I think lolOne of the people above me suggested Shan Go. Cute name! And it means mountain dog =Dhope you have a great time with your new member of the family! (I’m not allowed a Bernese until I’ve gone to uni AND qualified for the job I wanna do!)

  48. 48

    Distorted Defined Posted on Myth names that aren’t couolr dependent:Greek: Athena, Artemis, Demeter, ThalassaEgyptian: Isis, Hathor, Bastet (cat headed goddess)Norse: Freyja, Sif (Thor’s wife)Colour dependent:Nyx (Greek female primordial goddess of night)Styx (titan of the underworld)Geeky names:Astoria, Sway (x-woman/gone in 60 seconds), Shadowcat (x-woman), Mila (after Mila Jovovich of resident evil films), Polaris (star/x-woman), , Harley Quinn (batman), Petra (ancient city/x-woman), Evey (pronounced e-v from v for vendetta), Pixel, Mozilla, Aurora, Selene

  49. 49

    I think the bttoun should be more tightly integrated with Buzz. Maybe when you hover over the +1 bttoun, a small text balloon could pop up offering you the possibility to “also share on Buzz”. That way you could, if you wanted to, also state WHY you think that link is worth visiting.


↑ Back to top