O'Reilly

Create Twitter-Style Dropdowns Using jQuery

By on  
Twitter Dropdown

Twitter does some great stuff with JavaScript. What I really appreciate about what they do is that there aren't any epic JS functionalities -- they're all simple touches. One of those simple touches is the "Login" dropdown on their homepage. I've taken some time to duplicate that functionality with jQuery.

The HTML

<div id="menu1"><div class="relative">
	<a href="/demos" title="Popular MooTools Tutorials" id="dd1" class="dropdown" style="width:170px;text-decoration:none;"><span>Menu 1</span></a>
	<div id="dropdown1" class="dropdown-menu">
		<a href="/about-david-walsh" title="Learn a bit about me.">About Me</a>
		<a href="/page/1" title="The David Walsh Blog">Blog</a>
		<a href="/chat" title="#davidwalshblog IRC Chat">Chat</a>
		<a href="/contact" title="Contact David Walsh">Contact Me</a>
		<a href="/demos" title="CSS, PHP, jQuery, MooTools Demos">Demos &amp; Downloads</a>
		<a href="/js" title="ScrollSpy, Lazyload, Overlay, Context Menu">MooTools Plugins</a>
		<a href="/network" title="David Walsh Blog, Script &amp; Style, Band Website Template, Wynq">Network</a>
		<a href="/web-development-tools" title="JS, CSS Compression">Web Dev Tools</a>
	</div>
</div></div>

<div id="menu2"><div class="relative">
	<a href="/demos" title="Popular MooTools Tutorials" id="dd2" class="dropdown" rel="dropdown2" style="width:170px;text-decoration:none;"><span>Menu 2</span></a>
	<div id="dropdown2" class="dropdown-menu">
		<p>Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.</p>
	</div>
</div></div>

A series of DIVS wrapping a link (the dropdown "trigger") and a DIV containing the menu items.

The CSS

/* dropdowns: general */
a.dropdown { background: #88bbd4; padding: 4px 6px 6px; text-decoration: none; font-weight: bold; color: #fff; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; }
a.dropdown:hover { background: #59b; }
a.dropdown { position: relative; margin-left: 3px; }
a.dropdown span { background-image: url(toggle_down_light.png); background-repeat: no-repeat; background-position: 100% 50%; padding: 4px 16px 6px 0; }
a.dropdown.dropdown-active { color:#59b; background-color:#ddeef6; }
a.dropdown.dropdown-active span { background:url(toggle_up_dark.png) 100% 50% no-repeat; }
.dropdown-menu	{ background:#ddeef6; padding:7px 12px; position:absolute; top:16px; right:0; display:none; z-index:5000; -moz-border-radius-topleft: 5px; -moz-border-radius-bottomleft: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-top-left-radius: 5px; -webkit-border-bottom-left-radius: 5px; -webkit-border-bottom-right-radius: 5px; }
	.dropdown-menu p { font-size:11px; }
.dropdown-menu a:link, .dropdown-menu a:visited	{ font-weight:bold; color:#59b; text-decoration:none; line-height:1.7em; }
.dropdown-menu a:active, .dropdown-menu a:hover { color:#555; }

			* html .dropdown-menu { top:28px; }
			*+ html .dropdown-menu { top:28px; }

/* dropdowns: specific */
#menu1			{ float:left; margin-right:20px; }
	#dropdown1	{ width:150px; }
	#dropdown1 a	{ display:block; }
#menu2			{ float:left; }
	#dropdown2	{ width:150px; font-size:11px; }
.relative		{ position:relative; }

There's a lot of CSS involved but most of it is simple visual styling as opposed to styling for JavaScript's sake. Do, however, note where relative and absolute positioning is used. The outermost DIV may be positioned absolutely if you'd like. Also note that I'm not doing anything to accommodate for rounded corners in IE -- I recommend DD_Roundies for that.

The jQuery JavaScript

$(document).ready(function() {
	/* for keeping track of what's "open" */
	var activeClass = 'dropdown-active', showingDropdown, showingMenu, showingParent;
	/* hides the current menu */
	var hideMenu = function() {
		if(showingDropdown) {
			showingDropdown.removeClass(activeClass);
			showingMenu.hide();
		}
	};
	
	/* recurse through dropdown menus */
	$('.dropdown').each(function() {
		/* track elements: menu, parent */
		var dropdown = $(this);
		var menu = dropdown.next('div.dropdown-menu'), parent = dropdown.parent();
		/* function that shows THIS menu */
		var showMenu = function() {
			hideMenu();
			showingDropdown = dropdown.addClass('dropdown-active');
			showingMenu = menu.show();
			showingParent = parent;
		};
		/* function to show menu when clicked */
		dropdown.bind('click',function(e) {
			if(e) e.stopPropagation();
			if(e) e.preventDefault();
			showMenu();
		});
		/* function to show menu when someone tabs to the box */
		dropdown.bind('focus',function() {
			showMenu();
		});
	});
	
	/* hide when clicked outside */
	$(document.body).bind('click',function(e) {
		if(showingParent) {
			var parentElement = showingParent[0];
			if(!$.contains(parentElement,e.target) || !parentElement == e.target) {
				hideMenu();
			}
		}
	});
});

I've commented to the code to illustrate what each block does. In a nutshell:

  • I create placeholder variables which will keep track of the current menu, dropdown, and parent for the opened menu. This functionality is only included because I don't want more than one menu to be open at a time.
  • I create a function that hides the current menu -- this can be used from anywhere within the closure.
  • I cycle through each dropdown and add events to relevant elements to show and hide menus.
  • I add an event to the body to close the current menu if the user clicks outside of the menu.

That's it!

Be sure to check out the MooTools version.

Track.js Error Reporting

Recent Features

  • Responsive and Infinitely Scalable JS Animations

    Back in late 2012 it was not easy to find open source projects using requestAnimationFrame() – this is the hook that allows Javascript code to synchronize with a web browser's native paint loop. Animations using this method can run at 60 fps and deliver fantastic...

  • Introducing MooTools Templated

    One major problem with creating UI components with the MooTools JavaScript framework is that there isn't a great way of allowing customization of template and ease of node creation. As of today, there are two ways of creating: new Element Madness The first way to create UI-driven...

Incredible Demos

Discussion

  1. Looks great dude :)

  2. Goes off the left edge of my screen like the Mootools version… :-(

  3. @Dwight Blubaugh: I’ll address this at the end of the day. I have a few ideas.

  4. @Dwight Blubaugh: All that’s needed is to move the absolute positioning of the menu part. Instead of right:0, you’d use left:0.

  5. @David Walsh: I was able to fix this with:

    #menu1 {
    float:left;
    margin-right:20px;
    margin-left:100px;
    }

    However, I’ve tried both the JQuery and MooTools version, but the menus will not close (if the menus are clicked) or if I click outside them. Hmm…

    Cheers,
    Mike.
    Twitter: @bsodmike

  6. @David Walsh: I also had to do this, to get the ‘outside’ detection to work:

    body {
    	height:500px;
    }
    

    If ‘body’ was not styled, it would be a tiny bar at the top that the mouse would never reach.

  7. @Miichael

    Hiding the menu works with jQuery 1.4.1, but not jQuery 1.3.2. Are you using an older version of jQuery?

    Also, thank you for this tut!

  8. @Zac: I actually abandoned the JQuery version and got the MooTools version working (see my comments in the ‘other’ article). Thanks for the tip, I’ll check my JQ version and report back :)

  9. Pao

    This is nice tutorial for beginners :D
    Thank you..

  10. Chuck Conway

    Thanks for the demo. They work great. I appreciate your coding style, it’s elegant.

  11. Peo

    I would like to second this question, as the menu emulates the drop-down element of a form – wich has this behavior.

  12. Peo

    I’m sorry, i am reffering to: mike June 10, 2010 @ 10:30 am

  13. Zef

    Thanks alot man exactly what I was after!

  14. Gfoo

    I too would like to know how to make the dropdown close when pressing the up arrow/menu1

  15. Shawn Holman

    Hi! I just remade the JS but for some reason the JS that i used it does not make the button active. I used onclicks on the menu znd here is the JS that I used:

    function showmenu1() {
        $('#dropdown1').fadeToggle();
        $('#dropdown2').fadeOut();
    }
    function showmenu2() {
        $('#dropdown2').fadeToggle();
        $('#dropdown1').fadeOut();
    }
    

    This is more simple and to exit out the box all you have to do is click on the button agian, not outside

    • Shawn Holman

      I need help to make it active please help me

  16. Mattia

    I too would like to know how to make the dropdown close when pressing the up arrow/menu1

    • Mattia

      I’ve tried modifing jquery script in this way but no way :(
      Where am I wrong?

      $(document).ready(function() {
      	$(".sign_in").click(function()
      		{
      		$("#sign_box").show();
      		return false;
      		});
      	$(".sign_in").click(function()
      		{
      		$('.sign_in').addClass('active');
      		});
      
      	$(".sign_in.active").click(function()
      		{
      		$("#sign_box").hide();
      		return false;
      		});
      	$(".sign_in.active").click(function()
      		{
      		$('.sign_in.active').removeClass('active');
      		});				
      });
      

      Thanks in advance

  17. Better way to toggle menu when parent is clicked:

    /* function to show menu when clicked */
    dropdown.bind('click',function(e) {
    if(e) e.stopPropagation();
    if(e) e.preventDefault();
    if ( dropdown.hasClass('menu-open') ) {
    hideMenu();
    } else {
    showMenu();
    }
    });

  18. gmclelland

    @Florian and David Walsh – I took your changes and made a jsfiddle at http://jsfiddle.net/gmclelland/W8PgX/

    Now the hitting the “enter” key collapses the popup correctly.

    The only problem is that clicking the document doesn’t close the popup anymore.

    Any ideas on how to fix this?

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

Recently on David Walsh Blog

  • OSCON Portland:  Conference  Discount!

    O'Reilly puts on the best web industry conferences in the world.  These conferences include Fluent Conference, Velocity Conference, and the upcoming OSCON in Portland, Oregon from July 20-24.  Open Source Convention (OSCON) is a conference that focuses specifically on open source developers and the tools and possibilities...

  • Follow Redirects with cURL

    I love playing around with cURL. There's something about loading websites via command line that makes me feel like some type of smug hacker, just like tweeting from command line does. I recently cURL'd the Google homepage and saw the following: I found it weird that Google...

  • Developers Have WordPress, Amateurs Have Squarespace, Professional Designers Have the NEW Webydo!

    Web design platforms have traditionally come in one of two varieties. There are the solutions like WordPress and Drupal that are incredibly powerful, but an understanding of web development and coding is required to be able to use those platforms effectively. On the other side of the...

  • Chris Coyierâs Favorite CodePen Demos II

    Hey everyone! Before we get started, I just want to say it’s damn hard to pick this few favorites on CodePen. Not because, as a co-founder of CodePen, I feel like a dad picking which kid he likes best (RUDE). But because there is just so...

  • GSAP + SVG For Power Users: Motion Along A Path

    Now that the GreenSock API is picking up steam, there are many tutorials and Getting Started guides out there to provide good introductions to the library, not to mention GreenSock’s own Forum and Documentation. This article isn’t intended for beginners, but rather a...