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

  • Vibration API

    Many of the new APIs provided to us by browser vendors are more targeted toward the mobile user than the desktop user.  One of those simple APIs the Vibration API.  The Vibration API allows developers to direct the device, using JavaScript, to vibrate in...

  • 9 More Mind-Blowing WebGL Demos

    With Firefox OS, asm.js, and the push for browser performance improvements, canvas and WebGL technologies are opening a world of possibilities.  I featured 9 Mind-Blowing Canvas Demos and then took it up a level with 9 Mind-Blowing WebGL Demos, but I want to outdo...

Incredible Demos

  • MooTools Window Object Dumping

    Ever want to see all of the information stored within the window property of your browser? Here's your chance. The XHTML We need a wrapper DIV that we'll consider a console. The CSS I like making this look like a command-line console. The MooTools JavaScript Depending on what you have loaded...

  • Style Textarea Resizers

    Modern browsers are nice in that they allow you to style some odd properties.  Heck, one of the most popular posts on this blog is HTML5 Placeholder Styling with CSS, a tiny but useful task.  Did you know you can also restyle the textarea resizer in WebKit...

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

  • Convert Video to mp3

    Let's all be honest for a moment:  we've all ... not paid for ... music.  Whether it was via a file sharing app like Kazaa or Napster, or it was downloading and seeding on bittorrent, or maybe even downloading a music video and ripping its audio,...

  • Sort git Branches by Date

    I'll be first person to admit I don't do as much git repository maintenance as I should.  I rarely delete branches which have been merged, so a git branch execution shows me a mile-long list of branches that likely aren't relevant.  The best way to find branches I've recently...

  • Best Tools and Resources for Web Professionals in 2015

    Looking for the right resources to help you satisfy the needs of your clients? On the lookout for the best tools to help you increase your revenue? Searching for the right software to help you improve your business? Well, then you’ve come to the right place....

  • JavaScript Polling

    Polling with JavaScript is one of those ugly but important functions within advanced front-end user experience and testing practices.  Sometimes there isn't the event you can hook into to signify that a given task is complete, so you need to get your hands dirty and simply poll for...

  • OSCON Portland:  Conference Giveaway and 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...