Adding the “Extras on Demand” UI-Pattern with jQuery

The "Extras on Demand" pattern is described in Jennifer Tidwell's book, Designing Interfaces. In this tutorial we will explain what that pattern is, and how you can implement this into your interface using jQuery.

Today, javascript frameworks like prototype, mootools, and jQuery make writing javascript easy and fun. Whats more, because browsers and languages have evolved over the years (except Internet Explorer…), there are relatively few discrepancies. This means less work for you and more functionality for your users. Using techniques that are relatively simple, you can get a big return in usability. Unobtrusive javascript is the name of the game in terms of increasing your site’s usability.

Everyday patterns.

JQuery is the self-proclaimed “write less, do more” Javascipt framework. It essentially provides all the benefits of javascript using a syntax that is very familiar to front-end developers: that of CSS selectors (technically XPath selectors). That is to say, it’s easy to use for designers and fantastically extensible to developers. If you’re curious you can visit the jQuery homepage.

What We’re Building

In this post, I will detail one of the many tricks I have come across over the past two years developing interfaces. Using the idea of extras on demand helps you convey things to users in a more straightforward and intuitive way—some users don’t need all the content on a page up front. For example, if you’re letting people set their privacy settings, you probably have a lot of granular control you can offer users.

But you should ask yourself: do users need to detail settings for every piece of information on their profile? Most users won’t. In this case, what I would do is create a top-level security setting and provide a link so that intermediate-to-advanced users can drill deeper. This way, users new to the system can quickly get on their way while more perceptive users can be in full control.

So how do we do this?

To create the ”Extras on Demand” pattern requires 3 separate files working together to provide the proper visual and functional feedback to your users. They will be related like so:

How CSS and Javascript files link from our html page.
How CSS and Javascript files link from our html page.

“Extras on Demand” is a concept I learned from Jennifer Tidwell’s lovely book, Designing Interfaces: Patterns for Effective Interaction Design in which she describes the reasoning behind this pattern:

“A simple UI is often better than a complex one, especially for new users, or users who don’t need all the functionality you can provide. Let the user choose when to see the entire UI in its full glory — they’re a better judge of that than you are.”

Let’s get started

Go ahead and create the following files for this tutorial:

  • index.html
  • screen.css
  • application.js

Step One: Setup your index.html

First, let’s setup the link that will toggle the content we want to hide by default. Then we’ll add the div that has the optional content, like so:

<html>
  <body>
     <h4>Index.html</h4>
     <div id="wrapper">
      <a href="#hidden-content" class="collapsible">Show options</a>
      <div id="hidden-content">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at nisi quis neque auctor ultrices. Nunc sem dui, vestibulum et, placerat at, lobortis sed, turpis. Nulla a orci quis nulla posuere porta.</p>
      </div>
    </div>
  </body>
</html>

Step two: link in the jQuery and Stylesheet

Now we’ll add the jQuery. To do this you’ll need to import a javascript file. Because I primarily work with Ruby on Rails in my day to day development, I am apt to call this file application.js. The javascript will be responsible for hiding the content and then showing it on click.

To begin, we’ll need to add the following code to our page’s header:

    <script src="http://jqueryjs.googlecode.com/files/jquery-1.2.6.min.js" type="text/javascript"></script>
    <script src="http://brandonaaron.net/jquery/plugins/livequery/jquery.livequery.js" type="text/javascript"></script>
    <script src="application.js" type="text/javascript"></script>

What do these scripts do? The first one jquery-1.2.6 is jQuery, one of the most flexible and intuitive javascripts frameworks available today. The second one, jquery.livequery, is a plugin for jQuery that allows jQuery selectors to tap into elements on the page that have changed after the page loads. (In this case, we will be adding and taking away the class ‘active’ on elements, so we need to make sure jQuery can keep up.) Finally, we’re going to need to code our own javascript file to tell jQuery what we want done.

Step Three: Write application.js

With markup complete, let’s get our hands dirty and open up application.js. This file will do the “heavy lifting” jQuery for this trick. Here’s a summary of what the code will do. When the document loads, jQuery will scour the page for anchor tags (<a></a>) with class collapsible (<a class=”collapsible”>Hi!</a>). Upon finding these tags, jQuery will search for the div that they are responsible for collapsing/uncollapsing and hide that div. We use jQuery to hide the divs because it is responsible for eventually showing them. In this way, if a user doesn’t have javascript enabled by default, they can still access our webpage.

At this point we are left with links that are tied to hidden pieces of content. We then use jQuery to have our links toggle the display of their associated div. Ideally, when a link is “active,” that is, when it’s associated div is displayed, the link will obtain a class “active.” This way, we can use our CSS to present this active state to the user.

Here is our current application.js:

$(document).ready(function() {

  // Anchors

  $('a.collapsible:not(.active)').livequery('click', function(event) {
    var href = $(this).attr("href");
    $(href).show();
    return false;
  });

  $('a.active.collapsible').livequery('click', function(event) {
    var href = $(this).attr("href");
    $(href).hide();
    return false;
  });

  // Hide any elements that are not hidden but should be
  $('a.collapsible:not(.active)').each(function(){
    var href = $(this).attr("href");
    $(href).hide();
  });

});

Step four: Write screen.css

Now, we’ll add a little CSS to complete the effect.

*{
  margin: 0;
  padding: 0;
}

body{
	padding: 20px;
	background: #ccc;
	font-family: "HelveticaNeue-Light", Arial, Helvetica, Geneva, sans-serif;
}

h1{
	margin-bottom: 1em;
}

div#wrapper{
	width: 600px;
	margin: 0 auto;
	padding: 40px 20px;
	background: white;
}

div#hidden-content{
  border: 3px solid #ccc;
  margin-top: 1em;
  padding: 10px;
}

This css has a couple of rules. The first rule applies 0 margin and padding to every element. This is essentially the poor-man’s version of a Global Style Reset. The idea is, because various browsers style xhtml elements differently, we employ a “reset” of sorts to cancel this out. From there, we can apply styles to the body, heading (h1), wrapper and content divs—pretty straightforward.

Step five: Marvel at our work

We’re done! That wasn’t so hard, was it? The markup is rather simple but the effect is profound. Take a look below to see what we’ve accomplished. Don’t get too cozy, though. Now that we’ve got something to look at, I think we can add some finishing touches to elevate the experience.

We will borrow liberally from the way Apple presents this pattern.

Moving on: Elevating the experience

From here, we can do any of a number of small tweaks to make our links that much more compelling. To complete the effect, I downloaded the free (!!!) Silk icon library from that talented bloke over at famfamfam.com. I suggest you do as well.

Specifically, we’ll be using one of the bullet icons from that set. A simple photoshop-rotate gives us what we’re looking for. You can download the icons I used here. Using CSS we can now style our collapsible links differently depending on their state. I will style a.collapsible with a “right” arrow next to it, similar to how Apple has designed the “list-view” in OS X. In the same regard, a.collapsible.active will yield a “down” arrow to the left of the link. In addition we can change color or what-have-you. To do this, add the following to screen.css.

a.collapsible {
	padding-left: 16px;
	background: url(arrow-right.png) left center no-repeat;
	margin-left: -4px;
}

a.active.collapsible {
background-image: url(arrow-down.png); }

Lastly we’ll use jQuery to add a response state to our links. To do this, we simply add an empty span tag inside of our links, I prefer giving it class “response.” Then, when our link is active the “response” text will read: “Hide” (because that’s the action that the link will execute), whereas when the link is not active, the response text will read “Show.”

$(document).ready(function() {

  // Anchors

  $('a.collapsible:not(.active)').livequery('click', function(event) {
    $(this).addClass("active");
    var href = $(this).attr("href");
    $(href).show();
    return false;
  });

  $('a.active.collapsible').livequery('click', function(event) {
    $(this).removeClass("active");
    var href = $(this).attr("href");
    $(href).hide();
    return false;
  });

Below you can download the final example, complete with CSS and JQuery. Or, you can click to view this in your browser.

Where do we go from here?

Now that you’ve completed this tutorial, what would you do to change things? Sound off in the comments below!

About the Author

Andrew Maier

Andrew is a lifelong student of the design community, who co-founded the design publication UX Booth in 2008 to share his journey. He currently serves as its Editor-in-Chief. When he's not heading user-centered design initiatives for clients, Andrew dabbles in civic design. He lives in Seattle's Capitol Hill neighborhood.

Related Articles

12 Comments

  • David Kaneda Reply

    Good post, but should be updated to jQuery 1.3 — it’s reliable and would cut the need for Livequery.

  • Fire G Reply

    Great post Andrew, it did seem as if you were rushing through all the points though. Maybe if you had slowed down and explained each part of the jQuery (even though it’s not difficult at all if you know jQuery) it wouldn’t come off so fast.

    @David Kaneda: Really!? Guess I should get around to reading the jQ1.3 spec. huh.

  • shinokada Reply

    I don’t think you need to use livequery for this, since you are not calling it by Ajax. .click just be sufficient, isn’t it?

  • shinokada Reply

    This is another way you can do without livequery by using toggle. This will be smaller file size if you want to do only this function.

    $(document).ready(function() {

    $(‘a.collapsible’).toggle(
    function(event) {
    $(this).addClass(“active”);
    var href = $(this).attr(“href”);
    $(href).show(“slow”);
    $(this).find(‘span.response’).html(“Hide”);
    return false;
    },
    function(event) {
    $(this).removeClass(“active”);
    var href = $(this).attr(“href”);
    $(this).find(‘span.response’).html(“Show”);
    $(href).hide(“slow”);
    return false;
    });

    // Hide any elements that are not hidden but should be
    $(‘a.collapsible:not(.active)’).each(function(){
    var href = $(this).attr(“href”);
    $(href).hide();
    });

    });

  • Chris Robinson Reply

    Nice article but the only thing is ie6 isn’t liking the a.active.collapsible, is there a workaround for this?

    @ shinokada – I tried your code and it didn’t seem to work, would definitely like to use toggle instead of having to load the live query plugin

  • Chris Robinson Reply

    nevermind updated to 1.3 and changed .livequery to .live and it worked perfectly

  • Souika Reply

    Thank you, really good post. I did not know about this method before.

  • Janko Reply

    Great article! I use extras n demand widely in B2B applications, sometimes n combination with ajax calls.

    I’d just agree with shinokada that you don’t need .live() since structure hasn’t been created with ajax call.

    This particular case can be simplified to this:
    $(“a.collapsible”).click(function() {
    var target = $(this).attr(“href”);
    $(target).toggleClass(“collapsed”);
    });

    You just toggle .collapsed class that has only display:none. Also this class needs to be set for #hidden-content since its initial state is hidden.

Leave a Comment on This Article