Scrollable menus in Bootstrap

Okay kids, it’s geek time. I discovered a limitation in the dropdown menu when I was tooling around in Bootstrap. I found a way around it that preserved the look and didn’t require me to rewrite the markup, so I thought I’d share.
If you don’t know what Bootstrap is, it’s a CSS and JavaScript framework for web developers. I recently implemented it in the app I wrote for Chrome, Sticky Notes. (I know, I know. Really original name.) Anyhoo, I noticed a problem. If you had a lot of notes, this would happen:
Man, look at that. That sucker goes on forever. So how do you get to the items below the fold? You can’t. So, the first thing I did was give it a max-height. (I think 400px is a nice size, if it matters.) So that led to the next problem…
Oh yeah, overflow. Okay fine, I know how to fix that. Just give it an overflow: hidden
or in my case, this works nicely:
.dropdown-menu {
max-height: 400px;
overflow: hidden;
overflow-y: auto;
}
But now this happens:
Do you see it? It has scrollbars now, sure (and nice CSS customized scrollbars, thanks to Webkit), but the little bubble arrow is gone. That’s because the vertical overflow is set to scroll, and that arrow is actually the combination of the list’s ::before
and ::after
pseudoelements, set to show up outside the list itself.
I suppose it’s not that big of a deal, I mean, they’re just little arrows. It doesn’t detract from functionality, sure. But they have a certain asthetic, and I like it. And I’m gonna fix it, dangit!
Well, it turns out I’m not the only one to notice this. Someone else wrote an alternative dropdown plugin for jQuery, called jQuery Bootstrap-style Dropdowns. But it requires loading yet another plugin (something I didn’t want to do) and reworking the markup (something I didn’t want to do even more, since that note dropdown is built on the fly by other, custom JavaScript).
The pseudoelements on the list item might be hidden, but I could make new ones and put them on the parent link. So I wrote these styles:
a.dropdown-toggle {
position: relative;
}
The positioning on the parent link is just to set it up for showing the little arrow bubble. On to the important stuff:
a.dropdown-toggle::before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #CCC;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
bottom: -2px;
right: 7px;
display: none;
}
a.dropdown-toggle::after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid white;
position: absolute;
bottom: -2px;
right: 8px;
z-index: 1001;
display: none;
}
These are nearly identical to the pseudoelements defined for the list element, just adjusted for positioning along the bottom instead of the top. The last thing is the display: none
so that the arrow doesn’t show up all the time. The last thing, then, is to make sure they appear when the list appears:
.open > a.dropdown-toggle::before,
.open > a.dropdown-toggle::after {
display: block;
}
The dropdown toggles only work when Bootstrap’s menu plugin is active; when you click on a dropdown link, it gives a class of “open” to the link’s parent list item. I can use that, then, to target the opened list’s arrows. The end result, then, is this: a scrollable, max-heighted (it is too a word, I just made it up) dropdown menu with the bubble arrows intact.
Oh snap.
20 Comments
at ·
I’m pretty sure I only understood half of what you wrote!!!
at ·
Nice work. One question, how did you manage to make the scrollbars look that nice? I can see some jQuery plugins around; however, that seems to collide Bootstrap code when I try to aplly them to my Bootstrap dropdowns. Thanks!
at ·
I used Webkit-specific scrollbar CSS. See here:
http://css-tricks.com/custom-scrollbars-in-webkit/
at ·
Thanks! I’ll check it out.
at ·
Do you have any idea of how to apply this to a sub menu as your current solution only works for a main menu with no sub menus?
at ·
Hopefully you’re not still waiting on this answer, Jacob, but for others visiting this page – To make it work for the submenu, use this instead:
.dropdown-submenu:hover > .dropdown-menu {
max-height: 400px;
overflow: hidden;
overflow-y: auto;
}
at ·
Yes, that will work for children. But there’s no way to implement this for both the parent menu and its submenu. For that, you’d need a totally different approach.
at ·
Demo?
at ·
Great post! It inspired me to come up with another solution that has:
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)
Example: http://jsfiddle.net/XKEmy/
See comment: https://github.com/twitter/bootstrap/issues/1989
at ·
@Paul Nice!
@ugate thats awesome what you have going in the jsfiddle
at ·
thanx paul it’s very useful…
at ·
Good!!
at ·
Just Brilliant!!! Many thanks dude!!! Perfect fix!!!
at ·
Fantastic! Works like a charm. Thanks a ton…
at ·
what if drop down have submenu, those submenu will not be shown
at
I have the same issue, did you resolve it somehow?
at
I do not remember correctly, but I think I adjusted z-index in CSS
at ·
Thanks a lot
at ·
Hi Paul, can you help me unhide the scroll bar of my searchbox results. As you can see in my attached screenshot there’s no vertical scrollbar to see the other results. Please help me. https://uploads.disquscdn.com/images/7792b800b7fd62aaeeeb8ed3caa5cf2dea134b47812ecfa03f85883dfde0ea3f.png
at ·
thank you it works