How to Build a Lesson Drawer in jQuery, HTML, and CSS

Mark Cipolla
Mark Cipolla
Share

In the spirit of showing how things are done at SitePoint‘s sister company Learnable—a new site where anyone can create an online course about anything at all, and then sell access to that course—I’m going to run you through a small component of Learnable’s student view: the lesson drawer. I’ve simplified the layout and styling a little so that you can easily understand what’s going on, but the JavaScript is exactly the same. In this post, I’ll cover the HTML (including some of the new HTML5 elements), CSS, and JavaScript (with a little help from jQuery) needed to build a drawer. The drawer is a large container that holds a list of the lessons in a course, which can be opened by a button. The lessons are represented by a clickable thumbnail. To view an example of what we’ll be building, check it out here.

The HTML: the Structure

<section class="clearfix" id="lessonBuilder">
  <span id="lessonsTabTarget"><a href="#">Show Lessons</a></span>
  <nav id="lessonsTab" style="display: none;">
    <h1>Lessons</h1>
    <ul class="clearfix">
      <li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
      <li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
      <li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
      <li class="tab"><a href="#"><img src="thumbnail.jpg" /></a></li>
    </ul>
  </nav>
</section>
If you’re unfamiliar with HTML5, you’ll see I’ve used a few tags that will be new to you. The section is used to describe sections of your site, and the nav tag is used to contain navigation elements. The HTML5 tags help to reduce “div-itis”; for example, where you may have <div id="section"></div>
and <div id="nav"></div>. Apart from the new tags, it’s basically standard HTML. The unordered list would contain the linked thumbnails.

The JavaScript: the Magic

var LEARNABLE = {};
/**
  * Initialises the Lesson Drawer
  */
LEARNABLE.lessonDrawer = (function () {
    var init = function () {
        $("#lessonsTab").hide();
        $('#lessonsTabTarget').toggle(function() {
            $(this).addClass("shown").children('a').html("Hide Lesson Navigator");
            $("nav#lessonsTab").show("slow");
            return false;
        }, function() {
            $("nav#lessonsTab").hide("slow");
            $(this).removeClass("shown").children('a').html("Show Lesson Navigator");
            return false;
        });
    };

    // Public API
    return {
        init: init
    };
})();

$(document).ready(function() {
    LEARNABLE.lessonDrawer.init();
});
The JavaScript is where it becomes interesting. I’m going to proceed through this step by step, building it the way I would write it while explaining along the way.
var LEARNABLE = {};
This creates an object that will contain the functions for your page. We’ve named it LEARNABLE
, as it “namespaces” your functions. This form of writing JavaScript is called the module pattern. It’s a great way to structure your JavaScript for a number of reasons:
  • It reduces the number of global variables, as they are evil.
  • You can easily have lots of functions working together without affecting other scripts you may have running.
  • It’s relatively straightforward to maintain and work on.
  • Other developers involved in the project will be able to see what’s going on easily.
var LEARNABLE = {};
/**
  * Initialises the Lesson Drawer
  */
LEARNABLE.lessonDrawer = (function () {
    var init = function () {

    ...

    };

    // Public API
    return {
        init: init
    };
})();
Now we create our functions. I’ve named it lessonDrawer, and as it’s a part of the LEARNABLE
codebase, it becomes LEARNABLE.lessonDrawer. LEARNABLE.lessonDrawer is a function, so it is written as = (function (){, then the code, and is closed with })();. Here are the outside bits of the function:
LEARNABLE.lessonDrawer = (function () {

    ...

})();
Count the parentheses, and you’ll see that there’s an extra set of () at the end. This means it is self-executing; when your browser has downloaded this script, it will run it, allowing it to be accessed by any other JavaScript function in your script. Well, sort of.
    var init = function () {

    ...

    };

    // Public API
    return {
        init: init
    };
This little bit of trickery means that within the lessonDrawer function there are further functions, in this case called init. The tricky part is that at the end of the lessonDrawer
function, it will return to your script a way to gain access to the init function. You may ask, what’s the big deal? Let’s say we changed it a little:
var LEARNABLE = {};
/**
  * Initialises the Lesson Drawer
  */
LEARNABLE.lessonDrawer = (function () {
    var init = function () {

    ...

    };
    var otherThing = function () {

    ...

    };

    // Public API
    return {
        init: init
    };
})();
Because we’ve specifically said that we only want the init function available, no function outside of lessonDrawer can touch the function named otherThing
. It’s safe inside its parent function. You can’t accidentally run it and, more importantly, when you give it to other developers, they can only use it the way you’ve specified. Now to the insides of the init function:
$("#lessonsTab").hide();
First, we hide the #lessonsTab, which is our nav container. We do that in this function so that JavaScript-less users can still see the lesson drawer:
$('#lessonsTabTarget').toggle(function() {

    ....

}, function() {

    ....

});
The jQuery Toggle method displays or hides elements that it’s told about. The first half between the $('#lessonsTabTarget').toggle(function() { and }); means that when it’s clicked, it will show the lesson drawer. Its counterpart, between the function() { and closing });
, will hide the lesson drawer if it’s open:
    $(this).addClass("shown").children('a').html("Hide Lesson Navigator");
    $("nav#lessonsTab").show("slow");
    return false;
This is the code for showing the lesson drawer. I’ll now explain it line by line for you:
$(this).addClass("shown").children('a').html("Hide Lesson Navigator");
$(this) means whatever its parent is talking about (in this case, it’s the $('#lessonsTabTarget')
. I’ve been assuming you know what $('#lessonsTabTarget') means, but for those who’ve been playing at home, it asks jQuery (represented by the $) for any elements that have an ID of lessonsTabTarget. We add a class called “shown" to $(this)
, and then look through its children for an anchor. Looking back at the HTML structure we’re using, this is <span id="lessonsTabTarget"><a href="#">Show Lessons</a></span>, and on the child anchor we change the text (or its HTML) to the next text (“Hide Lesson Navigator”) as an instruction to the user that if they click the button, they will hide it).
$("nav#lessonsTab").show("slow");
Now we tell it to find the nav#lessonsTab and make it appear slowly. The jQuery Show method accepts a few arguments, the first being how long you want it to take to show an element. Instead of "slow"
, you can use "fast" or the number of milliseconds, where 1,000 means one second (as this is typed as an integer, no quotation marks are necessary, unlike "fast" and "slow").
return false;
We return false
to stop the browser from following the link. (As it is, it doesn’t go anywhere, but the <a href="#" would make the page jump to the top without returning false). To summarize:
  • Set up an unobstructive JavaScript function any time the page contains a #lessonsTabTarget element.
  • Add a class (telling the CSS that it’s “shown“).
  • Change the button text.
  • Open the lesson tab drawer.
  • Stop the page from following the link.
The second half is exactly the opposite! It hides the lesson drawer, removes the “shown” class name, and changes the text back. It also stops the browser from following the link. On a side note, the return false always needs to be the last thing in your function. Lastly, we need to run the code. Our final task is to tell the document that when it’s downloaded all its resources (JavaScript and CSS, as well as images), or when it’s ready, to run the init()
function. To access the init() function, you have to use its full name: LEARNABLE.lessonDrawer.init();.
$(document).ready(function() {
    LEARNABLE.lessonDrawer.init();
});

The CSS: the Polish

Adding the CSS is the last bit needed to make this a really great component.
/* HTML5 tags */
header, section, footer, aside, nav, article, figure {
	display: block;
}

#lessonBuilder {
  min-height: 200px;
  width: 940px;
  margin: 0 auto;
  position: relative;
}

nav#lessonsTab {
  background-color: #26414A;
  width: 940px !important;
  margin: 0 auto;
  opacity: 1 !important;
  padding: 30px 0;
  z-index: 1;
  display: none;
}

nav#lessonsTab h1 {
  color: white;
  font-size: 18px;
  margin: 0 0 0 45px;
}

nav#lessonsTab ul {
  list-style: none;
  padding: 20px 0 0 45px;
  margin: 0;
}

nav#lessonsTab ul li {
  float: left;
  margin: 0 15px 40px 0;
  padding: 4px;
  height: 70px;
}

nav#lessonsTab ul li:hover {
  background-color: #C9EFFB;
}

nav#lessonsTab ul li a {
  width: 100px;
  display: block;
  text-decoration: none;
}

nav#lessonsTab ul li a img {
  border: none;
}

#lessonsTabTarget {
  border-top: 2px solid #3F6D7B;
  width: 940px;
  display: block;
  z-index: 2;
  margin-top: -2px;
  text-decoration: none;
}

#lessonsTabTarget a {
  background: #283D44 url('lessonnav.png') top left repeat-x;
  display: block;
  padding: 7px 20px;
  position: absolute;
  right: 0;
  top: 0;
  color: white;
  width: 170px;
  text-align: center;

  -moz-border-radius: 0 0 5px 5px;
  -webkit-border-radius: 0 0 5px 5px;
  border-radius: 0 0 5px 5px;

  font-weight: bold;
  font-size: 15px;
  text-decoration: none;
  text-shadow: 0 1px 1px #333;
}

#lessonsTabTarget.shown a,
#lessonsTabTarget a:hover {
  background: #283D44 url('lessonnav.png') 0 -35px repeat-x;
}

/* http://perishablepress.com/press/2008/02/05/lessons-learned-concerning-the-clearfix-css-hack */
.clearfix:after {
	clear: both;
	content: ' ';
	display: block;
	font-size: 0;
	line-height: 0;
	visibility: hidden;
	width: 0;
	height: 0;
}

.clearfix {
	display: inline-block;
}

* html .clearfix {
	height: 1%;
}

.clearfix {
	display: block;
}

In Conclusion

This nice modular component is a real-world example of effectively using JavaScript (in this case, jQuery), HTML (with some HTML5 stuff), and CSS together. As I mentioned, it’s in use in Learnable, the place where you can take or create a course online on any subject.
note:Want more?
If you want to read more from Mark, subscribe to our weekly web design newsletter, The SitePoint Design View.
I hope you enjoyed (and understood) it. If you have questions, please feel free to ask via the comments below.

Frequently Asked Questions (FAQs) about Building a Lesson Drawer in jQuery, HTML, and CSS

How can I add more content to the drawer?

Adding more content to the drawer is quite simple. You just need to add more HTML elements within the drawer’s div. You can add text, images, links, or even other HTML elements like lists or tables. Remember to use appropriate HTML tags for each type of content. Also, ensure that the content fits within the drawer’s width and height. If the content exceeds the drawer’s dimensions, you may need to add a scrollbar using CSS.

Can I use this drawer on a mobile device?

Yes, you can use this drawer on a mobile device. The drawer is responsive, which means it adjusts its size and layout based on the screen size. However, you may need to adjust the drawer’s dimensions and the size of the content within it to ensure it displays correctly on smaller screens. You can use CSS media queries to apply different styles for different screen sizes.

How can I change the direction of the drawer?

The direction of the drawer can be changed by modifying the CSS. By default, the drawer slides in from the left. If you want it to slide in from the right, you can change the ‘left’ property to ‘right’ in the CSS. Similarly, you can make the drawer slide in from the top or bottom by using the ‘top’ or ‘bottom’ property instead.

Can I add multiple drawers to a page?

Yes, you can add multiple drawers to a page. Each drawer should have a unique id so that it can be controlled independently. You can use the same jQuery function to control all the drawers, but you need to pass the id of the drawer as a parameter to the function.

How can I change the speed of the drawer?

The speed of the drawer can be changed by modifying the jQuery function. The ‘animate’ function has a duration parameter that determines the speed of the animation. By default, the duration is 200 milliseconds. You can increase or decrease this value to change the speed of the drawer.

Can I add a close button to the drawer?

Yes, you can add a close button to the drawer. You need to add a button element within the drawer’s div and use jQuery to add a click event to the button. When the button is clicked, the drawer should be hidden. You can use the ‘hide’ function in jQuery to hide the drawer.

How can I make the drawer always visible?

To make the drawer always visible, you can remove the jQuery function that hides the drawer. Alternatively, you can set the ‘display’ property of the drawer’s div to ‘block’ in the CSS. This will make the drawer always visible, regardless of any jQuery functions.

Can I use this drawer with other JavaScript libraries?

Yes, you can use this drawer with other JavaScript libraries. However, you need to ensure that there are no conflicts between jQuery and the other libraries. You can use the ‘noConflict’ method in jQuery to avoid conflicts.

How can I add a scrollbar to the drawer?

You can add a scrollbar to the drawer by using CSS. If the content within the drawer exceeds the drawer’s dimensions, a scrollbar will automatically appear. You can use the ‘overflow’ property in CSS to control the scrollbar. If you set ‘overflow’ to ‘auto’, a scrollbar will appear only when necessary.

Can I use this drawer without jQuery?

While this drawer is built using jQuery for simplicity and ease of use, it is possible to build a similar drawer using pure JavaScript. However, this would require more complex code and a deeper understanding of JavaScript. If you are comfortable with JavaScript, you can use the ‘document.getElementById’ method to select the drawer and the ‘style’ property to control its visibility and position.