Grow your CSS skills. Land your dream job.

Unobtrusive Dropdown Page Changer

Published by Chris Coyier

Using a <select> dropdown menu to create navigation isn't as common as it once was, but it's still around. It got ripped on pretty good for being an inaccessible / obtrusive. Indeed a lot of the scripts you'll find out there for creating a menu like this are this way. Bummer. Let's make one that works with OR without JavaScript!

View Demo

The OBTRUSIVE Way

<form>
    <select onchange="window.open(this.options[this.selectedIndex].value)">
        <option value="">Go to page...</option>
        <option value="http://css-tricks.com/">CSS-Tricks</option>
        <option value="http://digwp.com/">Digging Into WordPress</option>
        <option value="http://quotesondesign.com/">Quotes on Design</option>
    </select>
</form>

Inline JavaScript... it works, but only if JavaScript is enabled. Without, you'll have a dropdown menu that does absolutely nothing.

The UNOBTRUSIVE Way

<form id="page-changer" action="" method="post">
    <select name="nav">
        <option value="">Go to page...</option>
        <option value="http://css-tricks.com/">CSS-Tricks</option>
        <option value="http://digwp.com/">Digging Into WordPress</option>
        <option value="http://quotesondesign.com/">Quotes on Design</option>
    </select>
    <input type="submit" value="Go" id="submit" />
</form>

Pretty similar, but no inline JavaScript. Instead we give the form and ID we will use later to target. The form now POSTs to itself, and we have added a submit button, so the form is functional. The select now has a name value, so when the submit button is pressed, it will POST a value.

At the very top of our page, we'll check for a POST value from that form. If it is there, we'll redirect the page to that value.

<?php
	if (isset($_POST['nav'])) {
		 header("Location: $_POST[nav]");
	}
?>

No JavaScript needed at all, the page redirect is handled entirely via server-side PHP. NOTE: this is just the way-simplified PHP. You should probably sanitize that submitted value before passing it to the header function (esp. if running PHP prior to 4.4.2 or 5.1.2) to prevent "header injection" attacks.

We can make it behave identically to the obtrusive method though, with just a few lines of jQuery.

  1. Hide the submit button.
  2. When the select is changed...
  3. Redirect to value of option
$(function() {

    $("#submit").hide();

    $("#page-changer select").change(function() {
        window.location = $("#page-changer select option:selected").val();
    })

});

View Demo

Update

Reader David Vandenbroek writes in:

I found that using:

<select onChange="window.open(this.options[this.selectedIndex].value)"> 

opens a Popup warning dialog, and if allowed, a new window on iPhone/iPad when iOS Safari has the setting 'Block Pop-ups' set to OFF. When the setting is set to ON, nothing happens.

To avoid both undesirable behavior, I used :

<select onChange="window.location.replace(this.options[this.selectedIndex].value)"> 

instead.

Comments

  1. Permalink to comment#

    I am freaking out I have been searching around for an hour for this EXACTLY! I said to myself, “I know that CSS-TRICKS will have it, let me take a look.” No search needed. Thanks so much for such a comprehensive site.

  2. TeMc
    Permalink to comment#

    Also nice to note that the unobtrusive way also doesn’t force a new window.
    Or is that another cause :D

  3. Permalink to comment#

    Isn’t it smart to have some sort of validation before the header function? Or am I missing something here?

    • Rob
      Permalink to comment#

      This would be one way:

      $dropdown_nav = array("http://www.google.com","http://www.css-tricks.com","http://www.yahoo.com");
      
      if ($_GET['page_nav'] && in_array($_GET['page_nav'],$dropdown_nav)) {
      	header("Location:".$_GET['page_nav']);
              exit();
      }
      
      // Loop through the array as an option to select form here
  4. Permalink to comment#

    It’s funny.Most of the time I got projects where client ask for something .First thing I do is check out the css-tricks and all the time I’m surprised ,yes there is new post and it’s exactly what I’m looking for.It’s like this dude is reading my mind!

  5. Permalink to comment#

    I probably won’t find this useful, but very nice though :P

    Another thing, there was once an article about no-css no-images solutions, and it seems to have vanished. Where is it? Thanks :P

  6. Naomi
    Permalink to comment#

    i like the new design css tricks !

    nice work chris! ..

    Kiss (K)

  7. DougS
    Permalink to comment#

    would love to see how to style these

  8. Marcus
    Permalink to comment#

    Nice… Less then a week ago i thought a feature like this would make a nice addition to my custom startpage at work, just didn’t take the time to look up how it’s done yet. Your timing couldn’t be much better.

    Thanx.

  9. Permalink to comment#

    This is cool. Falls back nicely when Javascript is disabled. I agree with Kristoffer, the url should be validated/checked before it goes into header().

    You should also put an exit; after header() to prevent the code below the header() call from executing.

    See the PHP manual page for the info: http://nl.php.net/manual/en/function.header.php

  10. Permalink to comment#

    I never seemed to like drop down navigation menus, however I might actually consider implementing something like this, given the right circumstances. Nice post!

  11. Helen
    Permalink to comment#

    Chris, I have to admit that do not really get the clue how to get the unobtrusive working. A new podcast culd help :)

  12. Permalink to comment#

    Using combobox for page selection is very bad user interface design. Always use anchors for that purpose and think about PDA/Mobile users.

  13. Chris
    Permalink to comment#

    The downside is that this kind of navigation isn’t accessible at all. What I did was HTML like

    <ul class="dropdown">
      <li><a href="http://css-tricks.com/">CSS-Tricks</a></li>
      <li><a href="http://digwp.com/">Digging Into WordPress</a></li>
      <li><a href="http://quotesondesign.com/">Quotes on Design</a></li>
    </ul>

    And a javascript that converted the html to a select box.
    That’s because our designer loved to use select boxes as a navigational element which is imho just wrong, because it’s an abusive use of a form element.
    I prefer just using the ul and styling it as a kind of menu using either suckerfish or neat javascript effects.

    • Benjamin
      Permalink to comment#

      This is fine, if you only have 3 selections to choose from.

      However, I plan to use this for selling tickets to concerts/events using Brown Paper Tickets. And, we have 20 events a month. That gets a bit unwieldy in a list.

      This is a good solution.

    • Chris
      Permalink to comment#

      My point is that you either rewrite the list via Javascript to a select box (which enables users w/o javascript and search engines) or to use css to style a list like a select box (by setting it to position:absolute, it’s height to one line and a hover to let it expand (optionally via scriptaculous)).
      So you can take best of both worlds.

  14. Permalink to comment#

    I’m with Dmitry here. I am struggling to see the point of using a form element to provide navigation – it’s non semantic and bad usability in my opinion. Why not use a styled list and if you really must, a bit of JS.

    • Aaron
      Permalink to comment#

      I don’t normally like these solutions, but its perfect for a sub menu mobile navigation for smaller sites!

  15. Permalink to comment#

    So now I have to write all my pages in PHP just so that I can have a semi-inaccessible navigation that will be ignored by the search engines?

    Wheres the advantage?

    • Permalink to comment#

      YES. YOU HAVE TO REWRITE EVERYTHING THIS INSTANT.

      Erm. No. IF you ALREADY have a dropdown menu like this, THIS is a way you can make it a less obtrusive. And PHP isn’t a requirement, you can use and server side technology that can accept form data and do a redirect.

    • Helen
      Permalink to comment#

      James, if the links inside the form would be ignored by search engines, millions of websites would not be in the index. Spidering a page made by Dreamweaver is harder than ruling Afghanistan. It contains hardly anything what we call HTML. It is a hell of click-events. What I wanna say:
      If there’s a link, Google gets it.

  16. nice way to do it, thanks for sharing :)

  17. Permalink to comment#

    your blog is so cool! i am seeking ways to promote my blog. this is especially helpful. please visit my blog.
    http://www.ishtihari.blogspot.com

  18. Permalink to comment#

    Great job Chris. Thanks

  19. Laars
    Permalink to comment#

    This is a misuse of POST; it should use GET instead.

  20. Permalink to comment#

    yeah..this dude really can read our mind…thx Dude…

  21. Permalink to comment#

    Sent in via Hendrik Walter

    This is a way to combine the obtrusive method with the PHP stuff to make it work the same way, only without jQuery:

    <form action="" method="post">
        <select name="nav" onchange="window.open(this.options[this.selectedIndex].value)">
            <option value="">Go to page...</option>
            <option value="http://css-tricks.com/">CSS-Tricks</option>
            <option value="http://digwp.com/">Digging Into WordPress</option>
            <option value="http://quotesondesign.com/">Quotes on Design</option>
        </select>
        <noscript>
            <input type="submit" value="Go" id="submit" />
        </noscript>
    </form>
    
    <?php
            if (isset($_POST['nav'])) {
                    // you should validate $_POST[nav] here
                    header("Location: $_POST[nav]");
            }
    ?>
  22. Sorry Chris I personally think this is the worst article I’ve read on CSS Tricks.

    You appear to be endorsing a very poor practice by example.

    At the very least remove the onchange behaviour and get that “go” button out of the noscript.
    That’d make it at least usable to most people.

  23. Mirek
    Permalink to comment#

    It is better to use

    location.assign(this.options[this.selectedIndex].value)

    instead of

    window.location.replace(this.options[this.selectedIndex].value)

    because location replace is not in browser history and it dissalow back button

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".