Scrollable Twitter Bootstrap Menus
June 28, 2013 13 Comments
Twitter Bootstrap has some pretty nice features, but one of the more common practices left out of its component stack is the ability to have long dropdown menus that scroll their content. A quick search on Google brought up some possible solutions, but a lot of them involved JavaScript/Plug-ins or directly hacked into the CSS of bootstrap. Each of which have their own advantages (JavaScript allows for more control, CSS only prevents unnecessary DOM manipulations). However, I’ve typically find myself consumed in the abyss of hacks that worked, but just so happened to brake another functionality of the framework I’m using. Sure, the hack may work in a lot of situations… but just not mine 😦 So, instead of taking another performance hit with a JS solution or using just CSS that may have some unintended consequences, I decided to use a combination of CSS and HTML to tackle the problem. The use of a few extra HTML tags along with some *hopefully* less intrusive CSS will lessen the chances that I’d screw up the intended purpose of the component I’m trying to add the feature to!
Here are a few benefits that this approach will give us:
- No JavaScript
- Does not interfere with the layout/CSS of the menu you’re trying to scroll content for
- Works with multiple scroll-menu in the same dropdown-menu
- Works with dropdown-submenu
- Works in responsive mode and mobile/touch enabled
- Allows for static headers and footers that will not scroll with the content using the normal list items
- The scroll-menu will grow dynamically until it reaches the max-height (at which point it will show a vertical scrollbar for each scroll-menu)
Well, I’ll cut to the chase and give you the solution I came up with *because nothings more irritating than trying to search through all the wrong ways someone did something before you find the final solution* (or you can jump to the final JFiddle example)
CSS
/* So we wont impact the original bootstrap menu or it's pseudo call-out arrow the menu is wrapped in a sub dropdown-menu with a chained scroll-menu */ ul.scroll-menu { position: relative; display: inherit !important; overflow-x: auto; -webkit-overflow-scrolling: touch; -moz-overflow-scrolling: touch; -ms-overflow-scrolling: touch; -o-overflow-scrolling: touch; overflow-scrolling: touch; top: 0 !important; left: 0 !important; width: 100%; height: auto; max-height: 500px; margin: 0; border-left: none; border-right: none; -webkit-border-radius: 0 !important; -moz-border-radius: 0 !important; -ms-border-radius: 0 !important; -o-border-radius: 0 !important; border-radius: 0 !important; -webkit-box-shadow: none; -moz-box-shadow: none; -ms-box-shadow: none; -o-box-shadow: none; box-shadow: none; }
HTML
<!-- Example of a single scrollable dropdown-menu navigation (notice the placement of the "scroll-menu" class) --></pre> <ul class="nav"> <li class="dropdown"><a href="#" data-toggle="dropdown"> <b class="icon-th-large icon-white"></b> </a> <ul class="dropdown-menu"> <ul class="dropdown-menu"><!-- static non-scrollable menu header --></ul> </ul> <ul class="dropdown-menu"> <ul class="dropdown-menu"> <li class="disabled"><a href="#"><b>My Theme:</b></a></li> <li><!-- Here we have our dropdown-menu wrapper so we don't mess with the layout of the outer dropdown-menu --> <ul class="dropdown-menu scroll-menu"> <ul class="dropdown-menu scroll-menu"> <li><a href="#"><i class="icon-asterisk"></i> Start</a></li> <li><a href="#"><i class="icon-minus"></i> UI Lightness</a></li> </ul> </ul> <ul class="dropdown-menu scroll-menu"><!-- Keep adding more list items and watch how your menu will grow w/o a vertical scollbar until it reaches the max-height set in the scroll-menu class --></ul> </li> </ul> </ul> <ul class="dropdown-menu"> <ul class="dropdown-menu"><!-- static non-scrollable menu footer --></ul> </ul> <ul class="dropdown-menu"> <li class="disabled"><a href="#"> <i class="icon-chevron-up pull-left"></i> <i class="icon-chevron-up pull-right"></i> </a></li> </ul> </li> </ul> <pre>
Result
Now that we have a scroll-menu working that’s decoupled from our main dropdown-menu, lets try to add multiple scroll-menus to our main dropdown-menu (again, you can skip to the complete JFiddle example if you’d like):
HTML
<!-- Example of a multiple scrollable dropdown-menu navigation (notice the placement of the "scroll-menu" class as well as the "scroll-menu-2x" class that helps to cut the max-height down to about 1/2 the size of our normal scroll-menu max-height) --></pre> <ul class="nav"> <li class="dropdown"><a href="#" data-toggle="dropdown"> <b class="icon-key icon-white"></b> </a> <ul class="dropdown-menu"> <ul class="dropdown-menu"><!-- static non-scrollable menu header 1 --></ul> </ul> <ul class="dropdown-menu"> <ul class="dropdown-menu"> <li class="disabled"><a href="#"><i class="icon-group"></i> <b>My Groups</b></a></li> <li> <ul class="dropdown-menu scroll-menu scroll-menu-2x"> <ul class="dropdown-menu scroll-menu scroll-menu-2x"> <li><a href="#">User</a></li> <li><a href="#">Administrators</a></li> <li><a href="#">Some Other Group</a></li> </ul> </ul> <ul class="dropdown-menu scroll-menu scroll-menu-2x"><!-- Additional menu items omitted for brevity --></ul> </li> </ul> </ul> <ul class="dropdown-menu"> <ul class="dropdown-menu"><!-- static non-scrollable menu header 2 --></ul> </ul> <ul class="dropdown-menu"> <ul class="dropdown-menu"> <li class="disabled"><a href="#"><i class="icon-user"></i> <b>My Roles</b></a></li> <li> <ul class="dropdown-menu scroll-menu scroll-menu-2x"> <ul class="dropdown-menu scroll-menu scroll-menu-2x"> <li><a href="#">Core Users</a></li> <li><a href="#">Admin</a></li> <li><a href="#">Some Other Role</a></li> </ul> </ul> <ul class="dropdown-menu scroll-menu scroll-menu-2x"><!-- Additional menu items omitted for brevity --></ul> </li> </ul> </ul> <ul class="dropdown-menu"> <ul class="dropdown-menu"><!-- static non-scrollable menu footer --></ul> </ul> <ul class="dropdown-menu"> <li class="disabled"><a href="#"> <i class="icon-chevron-up pull-left"></i> <i class="icon-chevron-up pull-right"></i> </a></li> </ul> </li> </ul> <pre>
Result
…and last, but not least we have the famed dropdown-submenu. This is where a lot of other solutions either partially work or do not work at all. While the proposed hack I’m suggesting may not be perfect it seems to get us going with a minimal impact on the core bootstrap implementation. Most of the HTML below should look almost identical to the way the normal dropdown-menu / dropdown-submenu is laid out with the addition of an added “dropdown-menu scroll-menu“:
This is really useful, but any menu which is made scrollable prevents the use of nested submenus within that menu. My main menu is the monster: the submenus are pretty short. Is there a simple way to force submenus to display ‘outside’ the scrollable area?
(also the coding examples above seem to have a lot of repeated lines, so they’re pretty unhelpful)
Bootstrap has dropped support for submenus in version 3. So, I’m not sure you’ll find much support for them going forward. Bootstrap obviously didn’t supply support for off-screen submenus. So, I think that will require some javascript on your part to get it to work the way you want them to.
The example has a lot of repeated lines in order to illustrate a large amount of menu items within the menu. Without it, the scrollbars would not show up (as seen in the screen shot).
Hey, that’s a great tweak you’ve got there. Thanks a million! However, it is notable that I don’t see it working in mobile. Any ideas?
What version of bootstrap are you using? Any mobile browsers in particular that you cannot view them in? Also, can you view the menus using the JS fiddle?
How I can make it work with a simple Button with drop-down? I tried to implement it, but the menu is always open. Here’s what I’m doing. http://jsfiddle.net/veJf9/
Just remove the “display: inherit !important;” from ul.scroll-menu
http://jsfiddle.net/veJf9/1/
Thanks! Thank worked great :).
Last thing. I updated the example and there’s one thing I want know if its possible. When you expand the scrollable menu, as you can see, the container expands too, And the non-scrollable menu does not expand the container.
I forgot the link of the updated version: http://jsfiddle.net/veJf9/4/
Try http://jsfiddle.net/veJf9/6/ notice position, width and margin
You are a star! Thank you so much!!
Good work but not wirking on mobile browsers version (i.e. Chrome Mobile). I can’t select any menu item when is scrollable.
Ugate, thank you so much for this! It has helped me so much. I have a similar problem to Elias, but when I put in the fix you gave him, it caused another issue. When you click on the word partner in my jsfiddle, you’ll see the submenu overlays the menu item. I tried messing with the css, but couldn’t get it right. The fiddle is here: http://jsfiddle.net/ftLLH/ and the menu item with the issue is PARTNERS. Thanks!!!
The fiddle didn’t work in IE 11. Have you tested in IE? Just wondering.