hobwell
hobwell

Reputation: 538

How can I put a dropdown list in the header of a collapsed bootstrap navbar menu

tl;dr

How can I get a proper dropdown to appear next to the standard list button in a collapsed bootstrap navbar menu?

Details

With MVC 5 and Bootstrap 3 (3.3.2) I am wondering how I can put a drop down menu in the collapsed version of a navbar. The default behaviour is somewhat problematic.

I am trying to place a language selector in the top right of the page regardless of whether the menu is collapsed for mobile or not.

This is how it looks (and should continue to look) in the non-collapsed navbar:

Non-collapsed bootstrap dropdown in menu

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            @Html.ActionLink("Application name", "Index", "Home", New With {.area = ""}, New With {.class = "navbar-brand"})
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#MainMenu">
                <span class="glyphicon glyphicon-th-list"></span>
            </button>
        </div>
        <div class="navbar-collapse collapse" id="MainMenu">
            <ul class="nav navbar-nav">
                <li>@Html.ActionLink("Home", "Index", "Home")</li>
                <li>@Html.ActionLink("About", "About", "Home")</li>
                <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                <li>@Html.ActionLink("Survey", "Instructions", "Survey")</li>
                <li><a href="/LT/LocalizationAdmin/LocalizationAdmin.aspx">Localization</a></li>
            </ul>
            <ul class="nav navbar-nav navbar-right">
                <li>@Html.ActionLink("Register", "Register", "Account", routeValues:=Nothing, htmlAttributes:=New With {.id = "registerLink"})</li>
                <li>@Html.ActionLink("Log in", "Login", "Account", routeValues:=Nothing, htmlAttributes:=New With {.id = "loginLink"})</li>
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown">EN<b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li><a href="/LT/DE">DE</a></li>
                        <li><a href="/LT/EN">EN</a></li>
                        <li><a href="/LT/ES">ES</a></li>
                        <li><a href="/LT/FR">FR</a></li>
                        <li><a href="/LT/RO">RO</a></li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
</div>

I run into problems on mobile devices with this pattern. Below is what a user sees AFTER clicking on the language drop down (after hitting the list button). Notice the nav-bar on the right? Well, that bar doesn't show on mobile devices and so the user is left thinking that the drop-down doesn't do anything, not realizing that they have to scroll the list to get to the language choices.

Collapsed and undesirable bootstrap dropdown in menu

What I am looking to do is have a drop down (as in the first image) next to the list button, as in the image below but for the life of me I can't figure out how to do it.

Desired layout with the language selector being a drop-down

This is a close as I have been able to get, but a side effect of this is that the language selector aligns to the left when the menu is not collapsed. I don't really want the accordion, I'd much prefer the drop-down. Failing that, it would be nice if the language selector opened a list the same way as the list button does (ie.full width), rather than having it jammed up against the side.

Desired layout with the language selector as right-aligned accordion prefixed to the nav list

The code for the last image is as follows:

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            @Html.ActionLink("Application name", "Index", "Home", New With {.area = ""}, New With {.class = "navbar-brand"})
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#MainMenu">
                <span class="glyphicon glyphicon-th-list"></span>
            </button>
            <ul class="nav navbar-nav pull-right" style="width: 65px;">
                <li class="dropdown">
                    <a href="#" class="dropdown-toggle" data-toggle="dropdown" style="margin-right: 5px;">EN<b class="caret"></b></a>
                    <ul class="dropdown-menu">
                        <li><a href="/LT/DE">DE</a></li>
                        <li><a href="/LT/EN">EN</a></li>
                        <li><a href="/LT/ES">ES</a></li>
                        <li><a href="/LT/FR">FR</a></li>
                        <li><a href="/LT/RO">RO</a></li>
                    </ul>
                </li>
            </ul>
        </div>
        <div class="navbar-collapse collapse" id="MainMenu">
            <ul class="nav navbar-nav">
                <li>@Html.ActionLink("Home", "Index", "Home")</li>
                <li>@Html.ActionLink("About", "About", "Home")</li>
                <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                <li>@Html.ActionLink("Survey", "Instructions", "Survey")</li>
                <li><a href="/LT/LocalizationAdmin/LocalizationAdmin.aspx">Localization</a></li>
            </ul>
            <ul class="nav navbar-nav navbar-right">
                <li>@Html.ActionLink("Register", "Register", "Account", routeValues:=Nothing, htmlAttributes:=New With {.id = "registerLink"})</li>
                <li>@Html.ActionLink("Log in", "Login", "Account", routeValues:=Nothing, htmlAttributes:=New With {.id = "loginLink"})</li>
            </ul>
        </div>
    </div>
</div>

Does anyone have any idea how to accomplish this? Apologies for the length, but I wanted to be clear.

Upvotes: 0

Views: 15108

Answers (2)

hobwell
hobwell

Reputation: 538

This solution allows you to have a separate menu which mimics the behaviour of the default list when collapsed (http://www.bootply.com/iLLWQZauo5).

The basic idea is that you need to put your list data in twice and then use a bit of css to display the appropriate list at the appropriate time.

It requires a bit more code than my other posted solution, but is more flexible for long lists which may extend beyond the length of a mobile screen.

Menu:

<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <a class="navbar-brand" href="/LT/">Application name</a>
            <button class="navbar-toggle collapsed" aria-expanded="false" type="button" data-target="#MainMenu" data-toggle="collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <button class="navbar-toggle collapsed" aria-expanded="false" type="button" data-target="#LanguageMenu" data-toggle="collapse">
                EN<b class="caret"></b>
            </button>
        </div>
        <div class="navbar-collapse collapse" id="MainMenu" aria-expanded="false" style="height: 1px;">
            <ul class="nav navbar-nav">
                <li><a href="/LT/">Home</a></li>
                <li><a href="/LT/Home/About">About</a></li>
                <li><a href="/LT/Home/Contact">Contact</a></li>
                <li><a href="/LT/Survey/Instructions">Survey</a></li>
                <li><a href="/LT/LocalizationAdmin/LocalizationAdmin.aspx">Localization</a></li>
            </ul>
            <ul class="nav navbar-nav navbar-right">
                <li><a id="registerLink" href="/LT/Account/Register">Register</a></li>
                <li><a id="loginLink" href="/LT/Account/Login">Log in</a></li>
              <!--For when the navbar is NOT collapsed-->  
              <li class="collapse-hidden">
                <ul class="nav navbar-nav collapse-hidden">
                  <li class="dropdown">
                      <a class="dropdown-toggle" style="margin-right: 5px;" href="#" data-toggle="dropdown">EN<b class="caret"></b></a>
                      <ul class="dropdown-menu">
                              <li><a href="/LT/Home/Index/">EN</a></li>
                              <li><a href="/LT/Nach Hause/Index/">DE</a></li>
                              <li><a href="/LT/Accueil/Index/">FR</a></li>
                              <li><a href="/LT/Acasă/Index/">RO</a></li>
                      </ul>
                  </li>
              </ul>                         
            </li>
          </ul>
        </div>
        <!--For when the navbar is collapsed-->
        <div class="navbar-collapse uncollapse-hidden collapse" id="LanguageMenu" aria-expanded="false" style="height: 1px;">
            <ul class="nav navbar-nav">
                    <li><a href="/LT/Home/Index/">EN</a></li>
                    <li><a href="/LT/Nach Hause/Index/">DE</a></li>
                    <li><a href="/LT/Accueil/Index/">FR</a></li>
                    <li><a href="/LT/Acasă/Index/">RO</a></li>
            </ul>
        </div>
    </div>
</div>

CSS:

/**
 * hide menu items when collapsed
 */
@media screen and (max-width: 767px) {
    .collapse-hidden{
        display: none;
    }
}

 /**
 * hide menu items when NOT collapsed
 */
@media screen and (min-width: 768px){
    .navbar-collapse.collapse.uncollapse-hidden{
        display: none!important;
    }
}

/**
 * set the fore-color of text within navbar-toggle items
 */
.navbar-toggle {
    color: #FFF;
}

Upvotes: 0

hobwell
hobwell

Reputation: 538

So I found a way to accomplish this, but it isn't very pretty. I wouldn't recommend doing this unless you know your dropdown is going to be short enough to always fit on a mobile screen. (http://www.bootply.com/mzfCeWgt2u)

The basic idea is to separate the header into a left and right side and put the drop-down directly in the right-hand header so that the collapse styles don't apply to it. It requires a bit of css to make everything appear inline correctly. Your mileage may vary.

First, the menu:

<div class="navbar navbar-inverse navbar-fixed-top">
  <div class="container">
      <div class="navbar-header pull-left">
          <a class="navbar-brand" href="/LT/">Application name</a>
      </div>
      <div class="navbar-header pull-right">
          <a class="btn navbar-btn pull-right" style="margin-right: 5px;" href="#" data-toggle="dropdown">EN<b class="caret"></b></a>
          <ul class="dropdown-menu realign">
              <li><a href="/LT/DE">DE</a></li>
              <li><a href="/LT/EN">EN</a></li>
              <li><a href="/LT/ES">ES</a></li>
              <li><a href="/LT/FR">FR</a></li>
              <li><a href="/LT/RO">RO</a></li>
          </ul>
          <button class="navbar-toggle" type="button" data-target="#MainMenu" data-toggle="collapse">
              <span class="glyphicon glyphicon-th-list"></span>
          </button>
      </div>
      <div class="navbar-collapse collapse clear-collapse" id="MainMenu">
          <ul class="nav navbar-nav">
              <li><a href="/LT/">Home</a></li>
              <li><a href="/LT/Home/About">About</a></li>
              <li><a href="/LT/Home/Contact">Contact</a></li>
              <li><a href="/LT/Survey/Instructions">Survey</a></li>
          </ul>
          <ul class="nav navbar-nav navbar-right">
              <li><a id="registerLink" href="/LT/Account/Register">Register</a></li>
              <li><a id="loginLink" href="/LT/Account/Login">Log in</a></li>
          </ul>
      </div>
  </div>
</div>

And then the css:

/**
 * clear floated menu items when collapsed
 */
@media screen and (max-width: 767px) {
    .clear-collapse{
        clear: both;
    }
}

/**
 * realign the drop down when not collapsed
 */
@media screen and (min-width: 768px){
    .pull-right > .dropdown-menu.realign {
        left: auto;
        right: auto;
    }
}

/**
 * set the color of nav-bar anchors styled as btns
 */
.navbar-header .btn{
    color: #9D9D9D;
}
.navbar-header .btn:hover {
    color: #FFF;
}

I will also post another answer which handles the issue a bit more elegantly.

Upvotes: 2

Related Questions