kelvinluck.com

a stroke of luck

Progressive enhancement with jQuery example

Update: shAIR is now called Sharify so I’ve updated the links below to point to the new website.

As I previously wrote, we just launched a new product called shAIRSharify. The website was a great chance to implement some progressive enhancement using my favourite javascript library, jQuery. So I thought I’d take the chance here to explain some of the things I did and how they continue to work without javascript enabled. None of this is rocket science by any stretch of the imagination but I thought is was worthy of a quick description.

Since much of the functionality discussed below is behind a login in the admin panel I put together a little example sandbox page which demonstrates the points below.

Styled submit buttons

The beautiful site design from hoppermagic called for submit buttons which don’t really look like buttons at all. Styling a normal submit button is fairly limited and hard to do cross browser so instead I decided to use javascript to swap out the submit button for a normal link which has an event listener which submits the form. If js is disabled the user gets a normal, accessible submit button. If js is available then we know that we will be able to use javascript to submit the form.

The code in question looks like this:

$(':submit').each(
   function()
   {
      var $this = $(this);
      var f = this.form;
      var link = $('<a href="#">' + $this.val() + '</a>')
         .bind(
            'click',
            function()
            {
               $(f).trigger('submit');
               return false;
            }
         )
      $this.after(link).css({position:'absolute', top:'-2000px'});
   }
)

Note that rather than hiding the real submit button with visibility:hidden or display:none we instead just move it way off the screen. This means that you can still submit the form by pressing return in one of the form fields (IE doesn’t allow this if there is no visible submit field in the form).

Form validation

Using the validation plugin made it very quick and easy to add clientside validation to my forms. This doesn’t replace serverside validation but it means that you can inform your users of their errors and give them meaningful feedback quickly. One thing that I would love to see added to the validation plugin is some sort of hooks for when the error message is shown and hidden. I wanted my errors to animate nicely into and out of existence. I managed to hack in a slideDown on the appear by abusing the errorPlacement callback but I wasn’t able to animate the disappearance of the element.

The code related to the validation plugin looks like this:

$forms = $('.validated-form');
if ($forms.length) {
 
   $forms.validate(
      {
         errorPlacement: function(error, element)
            {
               element.after(error);
               error.hide().slideDown();
            }
      }
   );  
}

Note that I only try and call the validate method where I find forms with a class of validated-form. This is because I use the same javascript throughout my site but I only include the validate plugin (and add the validated-form class to forms) on pages where it is required. I would get errors complaining that the validate method couldn’t be found if I didn’t have the check.

Tooltips

Another easy one thanks to the jquery.simpletip plugin. None of the examples on that page seem to use the tooltip in a particularly gracefully degrading way though. In my case I decided to use the title element of the items I was creating a tooltip for to hold the text of the tooltip. This means that without javascript enabled people will still see (less pretty) tooltips. The code is very simple, it grabs the value of the title and passes it into the simpletip initialiser. We also need to remember to empty the title attribute so that the browser doesn’t display it’s tooltip as well as ours.

$('.tt').each(
   function()
   {
      var $tt = $(this);
      $tt.simpletip(
         $tt.attr('title'),
         {
            hook: {
               tooltip: 'topLeft',
               target: 'bottomLeft'
            },
            offset: [20, -5],
            stem: {
               corner: 'topLeft',
               color: '#000',
               size: 15
            }
         }
      ).attr('title', '');
   }
);

FAQs accordian

For the FAQs page I wanted to make it easy for people to scan the questions and then click on the one they wanted the answer for. And jquery made it really easy to add a bit of animation to this too. As an added extra I also add a CSS class to the relevant question heading which changes the direction of the arrow besides it. The answers are hidden by javascript on document ready so users without javascript will just see a normal list of questions followed by answers.

var $h2;
var $answer;
$('.answer').hide();
$('#faq h2').bind(
   'click',
   function()
   {
      if ($h2 && $h2[0] != this) {
         $answer.slideUp();
         $h2.removeClass('open');
      }
      $h2 = $(this);
      $answer = $h2.next();
      $answer.slideDown();
      $h2.addClass('open');
   }
)

Message for IE6 users

I spent a little bit of time making sure that the site was at least usable in IE6. But I didn’t want to waste too much time making sure everything looked perfect. So I decided to add a little message to the top of every page which encourages IE6 users to upgrade their browser. This way they are at least aware why things don’t look quite right and they can’t complain. Luckily, IE6 is a (slowly) dying beast and will be used by a very small proportion of the site’s target audience (developers who are using Adobe AIR).

Summary

So that’s a quick description of some of the simple steps we took to make the website as beautiful and easy to use as possible for people on modern browsers while making sure it is still accessible and available to people using older browsers or who have javascript disabled (for whatever reason).

With the tools and information web developers have at their disposal these days it is so easy to build a site in this manner that there really is no excuse for sites which are completely broken with javascript disabled. Hopefully these simple examples illustrate the some of the concepts behind progressive enhancement.

12 Comments, Comment or Ping

  1. The deco on the new http://www.shair.it looks absolutely fabulous, I am just reading the '/how-it-works' page. You took as you describe, "the simple steps" to make the website as beautiful on modern browsers and practical as possible, real well. Looks great in Chrome browser ... with javascript enabled, i'll try also without. I am new to jquery projects but I love the script already. All the best, and Ta.

    March 8th, 2009

  2. luke

    nice site but don't think the validation works? just submitted a totally empty form under 'contact' and it went through to the thankyou page.

    also random thought but got here from quasimondos mention of you a couple times for the flickr api flash tool you've done. is there an AS3 version of this?

    April 6th, 2009

  3. Hi Luke,

    Glad you like the site :)

    There is no validation on the contact form. I didn't see the need to validate it - people can't really fill it in "incorrectly". I guess I could check for a valid email address but my feeling was that if someone was trying to contact us and wanted a response then they would be careful to enter their correct email address... The validation is on all the forms within the admin panel where there is a need to prevent users making mistakes.

    I'm afraid there isn't a publically available as3 version of Flashr. I have the start of a version on my harddrive but it's not finished enough for release. To be honest, since XML parsing is so much quicker and easier in as3 using e4x it's probably not that hard to roll your own (depending on what features of the API you need). Or there is also as3flickrlib although I wasn't a great fan of that when I tried it out (hence starting a port of Flashr).

    Hope that helps,

    Kelvin :)

    April 6th, 2009

  4. Luke

    Ah, got it.

    Yeah XML is a whole lot easier in AS3. Coming more back to the post topic, jQuery is a fantastic library and the great documentation and critical mass it's obtained mean a lot of plugins and libraries are coming out now, similar to AS3 I guess. One thing I'm still stuck on though is connecting to external RSS feeds via jQuery. All the solutions I've seen so far require a PHP proxy to work....

    April 7th, 2009

  5. Simon

    Hi, I have found your article extremely helpfull to in helping me add enhancements for my forms.

    Im implementing your form submit link swap technique across a wide range of forms and Im having issues with the fact that because a lot of the form submits have a 'name="submit"' attribute, the click submit breaks. I was just wondering if you had any ideas as to how I could easily get round this, aside from changing the name attribute.

    Thanks in advance for any help you can give me, keep up the good work.

    April 8th, 2009

  6. Hey Luke!

    You could try using YQL to make a jsonp request out of the data like I do in this example:

    http://www.kelvinluck.com/2009/02/data-scraping-with-yql-and-jquery/

    Hope that helps,

    Kelvin :)

    April 8th, 2009

  7. Hi Simon,

    I'm a little confused... I don't think there are any name="submit" attributes in my code? The :submit jquery selector just selects every input with a type of submit (e.g. submit buttons) - they don't need any particular name (or indeed a name at all!).

    If you are still having problems then maybe I can help further if you can provide a link to your page which is displaying the problem,

    Cheers,

    Kelvin :)

    April 8th, 2009

  8. Simon

    Hi kelvin.

    Sorry I probably wasn't very clear. The name="submit" is in my form, not yours.

    http://www.mr-scraggy.com/test.html

    If you check out the link above, which is a basic html page, I have included two forms. The top one is copied out from the source code of your form. The bottom one is the markup from my form. Its not linked to any form scripts but you can see that if you click on sign up link for your form, the submit works. If you click on my one, it doesnt. I spent a while debugging and trying things out and the only thing that makes a difference is the name="submit" on my submit. if you take that out, the javascript works. Unfortunately for me, I'm not allowed to change the name="submit" on any of the forms so im stuck with it. Im very new to javascript so I don't really know how to overcome the issue. Any help or ideas would be very well received.

    Thanks,
    Simon

    April 8th, 2009

  9. Hi Simon,

    I've just done some investigation and I can see what is causing your problem. The problem is that form.submit is a pointer to the submit button in your case rather than being the submit() function which should submit the form. So when I try and trigger a form submit event it fails.

    I would highly suggest a way of changing the name attribute on the submit button. What is the reason you can't change it? Because serverside code is expecting it? I think using words like submit as the name of a form element is bad practice...

    If there is no way you can change it then you could change this line:

    $(f).trigger('submit');

    to:

    $this.trigger('click');

    As we can't trigger the submit event on the form itself (as it has been overwritten by the input type=submit element), instead I am triggering a click event on the original button. The problem is that it seems like any onsubmit handlers on the form don't run (or don't have the ability to return false and prevent the form from submitting). I noticed this on my test page because changing the code broke the validation. That may not be an issue in your case but it's worth being aware of...

    Hope that helps,

    Kelvin :)

    April 11th, 2009

  10. Simon

    Hi Kelvin.

    Thanks alot for all your help. The new method seems to work good.

    I agree about the naming of the attr. the problem has been that in my team Im not respnsible for all the old form scripts and when I requested the naming to be changed, the senior PHP developer said that it was goign to be too much hassle to change and test all the forms on the site. Im rolling this out accross 4 big sites and they dont want my new front-end projects to affect the older code that has been in place for several years.

    Im hoping to sort this naming out eventually, but in the meantime this is doing what I want so thankyou very much.

    I will post you up a link to the page as soon as its live on our server, its currently on our Dev server behind a firewall.

    Thanks again,

    Simon.

    April 23rd, 2009

  11. FYI, the Register form doesn't have any validation either - http://www.sharify.it/user/register .

    Whoops?

    ~James

    July 23rd, 2009

  12. Hi James,

    I didn't consider validation necessary for that page either. Presumably if someone is registering to show their interest in the Sharify service then they will put in their correct email address. The only validation I could do would be to check that the email address was a legal email address so this wouldn't guarantee they hadn't misspelt it or anything. And the comments field is totally optional so can't be validated. So it didn't seem to make much sense to add validation to this page. Then again, it is so easy to add that maybe I should have done just for the sake of completeness!

    Cheers,

    Kelvin :)

    July 23rd, 2009

Reply to “Progressive enhancement with jQuery example”