Close Sidebar

Simple Accordion Menu With JQuery & ASP.NET

In the following article I will show you how to create a simple accordion menu with JQuery and ASP.NET Visual Studio 2008.  There are many implementations of an accordion type menu on the web, including using JQuery UI and the ASP.NET AJAX Toolkit. For one reason or another these implementations did not work for me, so I decided to roll my own using JQuery and accomplish the following:

  1. Simple & valid markup
  2. Minimal JavaScript
  3. Auto slide open of the accordion menu based on the url
  4. Indication of which section is open and which link is active
  5. Degrade gracefully if JavaScript is turned off

If you look at the markup for the layout in the Master Page (‘MasterPage.master’), you’ll notice I’m using a three column CSS design and separated the menu and some content into user controls (located in the App_Controls folder).  None of this is pertinent to the accordion menu per se, but you may find that it is a good practice to separate out your design from the markup, as well as using user controls for content that will repeat on pages.

<div id="wrapper">
    <form id="form1" runat="server">
        <div id="page" >
            <!-- HEADER -->
            <uc1:head id="head2" runat="server" />
            <!-- LEFT CONTENT -->
            <div id='leftwrap'>
                <uc3:leftnav id="leftnav2" runat="server" />
            </div>
            <!-- MAIN CONTENT -->
            <div id="mainwrap">
            <div id="maincontent">
                <asp:ContentPlaceHolder id="main" runat="server">
                </asp:ContentPlaceHolder>
            </div>
            </div>
            <!-- RIGHT CONTENT -->
            <div id="rightwrap">
                <uc2:rightnav ID="rightnav2" runat="server" />
            </div>
            <!-- FOOTER -->
            <div id="footer">
                <uc4:footer id="footer2" runat="server" />
            </div>
        </div>
    </form>
</div>

The accordion menu markup is located in a user control called ‘leftnav.ascx’ (see below for the accordion menu markup).  Each menu heading item is comprised of an <h3> tag with a nested <a> tag. The link section is comprised of a simple <ul> wrapped with a <div>.  As you can see, the menu markup is relatively simple and straightforward.

<div id="accordion">

        <h3>
        <a href="javascript:void(0);" runat="server" id="aServices">Services</a></h3>

        <div class="acsection" runat="server" id="divServices">
        <ul>
            <li runat="server" id="liService1"><a href="service1.aspx">Service 1</a></li>
            <li runat="server" id="liService2"><a href="service2.aspx">Service 2</a></li>
        </ul>
        </div>

        <h3>
        <a href="javascript:void(0);" runat="server" id="aArticles">Articles</a></h3>

        <div class="acsection" runat="server" id="divArticles">
        <ul>
            <li runat="server" id="liArticle1"><a href="article1.aspx">Article 1</a></li>
            <li runat="server" id="liArticle2"><a href="article2.aspx">Article 2</a></li>
        </ul>
        </div>

        <h3>
        <a href="javascript:void(0);" runat="server" id="aProducts">Products</a></h3>

        <div class="acsection" runat="server" id="divProducts">
        <ul>
            <li runat="server" id="liProduct1"><a href="product1.aspx">Product 1</a></li>
            <li runat="server" id="liProduct2"><a href="product2.aspx">Product 2</a></li>
        </ul>
        </div>

    </div>

The JavaScript for the accordion menu only requires a few lines of code.  When the document is ready ($document.ready), I attach a click event using JQuery to each <h3> tag within an element with an id of ‘accordion’, which in this case is the wrapping <div> tag. To accomplish the opening and closing of the menu, only one line of code is needed.  When the <h3> item is clicked, the next <div> section is opened and all the sibling <div> sections are closed.  That is it!

$(document).ready(function() {

    // set up the accordion
    $("#accordion>h3").click(function() {
        $(this).next("div").slideToggle(500).siblings("div").slideUp(500);
    });

    // show active menu section
    setTimeout('$("#accordion>div.activesec").slideToggle(800)', 100);

});

To accomplish the auto opening and styling of the appropriate section and links based on the url, we’ll use a little C# code, JavaScript and CSS.  If you look at the code for ‘leftnav.ascx.cs’ below, I’m simply getting the page name and adding style classes to the appropriate tags.  I’m adding ‘active’ class to the <a> tag and ‘subactive’ class to the <li> tag to indicate that they are selected with a little arrow. In addition, I’m adding ‘activesec’ class to the <div> that wraps the links to highlight the top and bottom borders of the section (see below for the accordion CSS).  The ‘activesec’ class serves a dual purpose, as I will also use this class to select the active section to open.

protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            // get page
            string pageName = Request.Url.ToString().ToLower();
            int pos = pageName.LastIndexOf("/");
            pageName = pageName.Substring(pos + 1);

            switch (pageName)
            {
                case "article1.aspx":
                    this.aArticles.Attributes["class"] = "active";
                    this.liArticle1.Attributes["class"] = "subactive";
                    this.divArticles.Attributes["class"] = "acsection activesec";
                    break;
                case "article2.aspx":
                    this.aArticles.Attributes["class"] = "active";
                    this.liArticle2.Attributes["class"] = "subactive";
                    this.divArticles.Attributes["class"] = "acsection activesec";
                    break;
                case "service1.aspx":
                    this.aServices.Attributes["class"] = "active";
                    this.liService1.Attributes["class"] = "subactive";
                    this.divServices.Attributes["class"] = "acsection activesec";
                    break;
                case "service2.aspx":
                    this.aServices.Attributes["class"] = "active";
                    this.liService2.Attributes["class"] = "subactive";
                    this.divServices.Attributes["class"] = "acsection activesec";
                    break;
                case "product1.aspx":
                    this.aProducts.Attributes["class"] = "active";
                    this.liProduct1.Attributes["class"] = "subactive";
                    this.divProducts.Attributes["class"] = "acsection activesec";
                    break;
                case "product2.aspx":
                    this.aProducts.Attributes["class"] = "active";
                    this.liProduct2.Attributes["class"] = "subactive";
                    this.divProducts.Attributes["class"] = "acsection activesec";
                    break;
            }
        }
    }

If you look at the Javascript code above, you’ll notice that I’m using the setTimeout method to execute some code 100 milliseconds after the page has loaded.  Using JQuery selector, I’m sliding open a <div> with the class ‘acsection’ (which was set in the C# code), within an element with an id of ‘accordion’.

#accordion{
    list-style-type:none;
    margin:0;
    padding:0;
    width:170px;
}
#accordion ul{
    margin:0;
    padding:10px 0;
    margin-left:10px;
}
#accordion li{
    list-style-type:none;

}
#accordion li a{
    color:#666;
    text-decoration:none;
    padding:3px 0;
    display:block;
    padding-left:12px;
}

#accordion li a:hover{
    text-decoration:underline;
    background-repeat:no-repeat;
    background-position:left center;
}

#accordion li.subactive
{
    background-image:url(../images/lnbullert.gif);
    background-repeat:no-repeat;
    background-position:left center;
}

#accordion li a:focus{
    outline:none;
}
#accordion .acsection{
    border:dotted 1px #B3B3B3;
    margin:0;
    border-left:none;
    border-right:none;
    width:170px;
}

#accordion h3{
    margin:0;
    padding:5px 0;

}
#accordion h3:focus {
    outline: none;
}
#accordion h3 a{
    color:#777;
    text-decoration:none;
    display:block;
    padding-left:12px;
    background-image:none;
}
#accordion h3 a.active
{
    color:#555;
    background-image:url(../images/lnMbullert.gif);
    background-repeat:no-repeat;
    background-position:left center;
}
#accordion h3 a:focus{
    outline:none;

}

#accordion h3 a:hover{
    text-decoration:underline;
    color:#555;
    background-repeat:no-repeat;
    background-position:left center;
}

In the case when JavaScript is turned off in a user’s browser, I simply allow all the menu links to be visible. I include a few lines of JavaScript at the bottom of the Master Page (see code below) to hide all the <div> sections with an id of ‘acsection’.  That’s it!

   // set up accordion by hiding link sections
   // if no javascript then all links will be displayed as the below code
   // will not execute
   var styleObject = getCSSRule('#accordion .acsection');
   styleObject.style.display = 'none';

I hope you enjoyed this article and have found it useful.  Please comment or email me with any questions.  Happy Programming!

Recommended Reading

15 Comments

  1. Noman Aftab says:

    Thanks Steve, I used your code and converted into a dynamic accordion menu (links from DB).
    I just wanted to know if it is possible to show icons against each link (li item)?

    Regards,
    Noman Aftab

    • steve boschi says:

      Absolutely. You can try to add a background image to the li tag. Would you like me to email you an example?
      - Steve

      • Noman Aftab says:

        Hi,
        actually the background workaround will not work for me because in case of a selected , I have to show both background gradient (through css, as you show bullet) and icon simultaneously.
        and each item will have a different icon.
        even if a item is not selected, its icon will be shown.

        What I have done is, I have added an tag as a child control in just like is a child to .

        Thanks anyways.
        Noman Aftab

  2. Feysal says:

    That thing is really great. However,we would appreciate it even more if we could have the source code downloadable. Please can you do us that little favor?

  3. [...] Simple Accordion Menu With jQuery & ASP.NET (Steve Boschi) [...]

  4. Steve C says:

    Perfect timing for the project I’m working on.
    Thanks!

  5. [...] This post was mentioned on Twitter by amexn, Naveen Lagadapati. Naveen Lagadapati said: “Simple Accordion Menu With #JQuery & ASP.NET” #aspnet #tech http://j.mp/bTzCw0 [...]

  6. well done!nice job!