A simple accordion with jQuery, without worrying about off-by-one errors.

As you may well know, it is common in web development to include accordion menus on websites nowadays. It frequently hear people mention around the office how they’re currently working on, “yet another accordion”. Reusable code libraries aside (i.e. saving your accordion code for reuse later), I also often hear people mention difficulties getting the correct accordion row to expand. Whether it is that ALL the rows expand, or the wrong row.

That being said, I’ve put together this very simple example of how to always have the correct row expand or collapse:

<html>
<head>
    <script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.js"></script>
</head>

<body>
    <div class="accordion" style="width: 300px">
        <div class="row-group" style="border:1px solid black;">
            <div class="title"style="border:1px solid green;">
                Title
            </div>
            <div class="body" style="display:none; border:1px solid red">
                this is the body is the body is the body is the body
                 is the body is the body is the body is the body
                 is the body is the body is the body is the body
                 is the body is the body is the body is the body
            </div>
        </div>
        <div class="row-group" style="border:1px solid black;">
            <div class="title"style="border:1px solid green;">
                Title
            </div>
            <div class="body" style="display:none; border:1px solid red">
                this is the body is the body is the body is the body
                 is the body is the body is the body is the body
                 is the body is the body is the body is the body
                 is the body is the body is the body is the body
            </div>
        </div>
    </div>
<script type="text/javascript">
    $('.accordion').on('click', '.title', function(e) {
        var $rowGroup = $(e.target).parents('.row-group');
        $rowGroup.find('.body').slideToggle();
    })
</script>
</body>
</html>

What you’ll likely notice is a very handy jQuery method that most people seem unaware of, and that’s the .parents() method. $.parents() returns ALL parents of an element, all the way up to the document. (not to be confused with .parent() which only returns the element’s immediate parent). Additionally, by passing in a selector, you can find a specific element in that group of parents (grand parents, great grand parents, etc). in this case, we’re trying to find an element with a class of “row-group” in the chain of element ancestry. Granted, my example actually finds the immediate parent, and thus $.parent() would work, but it’s not always the case that the parent you want is the immediate parent.

Once we have the row-group, we’re then requesting the div.body element within that row group and expanding only that element, so we can be certain that we’ll never be expanding the wrong element.

Leave a Reply