How to create an accordion with AngularJS

In this tutorial, we will learn how to create an accordion using Angular.js. In this tutorial we will create a fully functional accordion in an Angular controller. In a follow up post, we will take our accordion out of the controller and abstract it into an Angular directive, making it fully dynamic and much more powerful. Let’s get started!

The HTML

<div ng-app>
    <div class="accordion__container" ng-controller="myCtrl">
        <div class="accordion__tab">
            <div class="accordion__tab-title" ng-click="openTab('tab one')">Tab 1</div>
            <div class="accordion__tab-content" ng-show="isOpenTab('tab one')">Tab content goes here!</div>
        </div>
        <!-- .accordion__tab -->
        <div class="accordion__tab">
            <div class="accordion__tab-title" ng-click="openTab('tab two')">Tab 2</div>
            <div class="accordion__tab-content" ng-show="isOpenTab('tab two')">Tab content goes here!</div>
        </div>
        <!-- .accordion__tab -->
        <div class="accordion__tab">
            <div class="accordion__tab-title" ng-click="openTab('tab three')">Tab 3</div>
            <div class="accordion__tab-content" ng-show="isOpenTab('tab three')">Tab content goes here!</div>
        </div>
        <!-- .accordion__tab -->
    </div>
</div>

Some basic HTML, if you look through you will notice some Angular attributes on some of the elements. ng-controller tells Angular what controller you want it to use for the code within that element. ng-click tells angular to do something when you click on that element. ng-show will either show/hide the element it is on based on whether or not what you pass into it evaluates to true/false. It shows the element if true, hides it if false. I will go into some more detail in the JS section where we outline more about the Angular code.

The CSS

.accordion__container {
    background: #eee;
    border: 1px solid #ccc;
    padding: 20px;
}
.accordion__tab {
    background: #aaa;
    color: #fff;
    border-bottom: 1px solid white;
}
.accordion__tab-title {
    background: #888;
    padding: 5px;
    cursor: pointer;
}
.accordion__tab-content {
    background: #999;
    padding: 20px;
}

The CSS used here is pretty basic. Just some styles for the demo, nothing necessary for functionality.

The Javascript (Angular!)

function myCtrl($scope) {
    // initiate an array to hold all active tabs
    $scope.activeTabs = [];

    // check if the tab is active
    $scope.isOpenTab = function (tab) {
        // check if this tab is already in the activeTabs array
        if ($scope.activeTabs.indexOf(tab) > -1) {
            // if so, return true
            return true;
        } else {
            // if not, return false
            return false;
        }
    }

    // function to 'open' a tab
    $scope.openTab = function (tab) {
        // check if tab is already open
        if ($scope.isOpenTab(tab)) {
            //if it is, remove it from the activeTabs array
            $scope.activeTabs.splice($scope.activeTabs.indexOf(tab), 1);
        } else {
            // if it's not, add it!
            $scope.activeTabs.push(tab);
        }
    }
}

Alright- now to the good stuff! The code is well commented, so you should be able to follow it down line by line and grasp what’s going on. If something isn’t clicking- feel free to comment below and I’ll help where I can! The function myCtrl() related directly to where we specify our ng-controller in our application. That’s the reason that within the ng-open you can put the isOpenTab() function (since isOpenTab() is defined within myCtrl()). In the code above, we instantiate an empty array variable. The idea here is that this variable will be home to each accordion piece that is currently open. The $scope.isOpenTab() function checks whatever you pass in against the array and returns true/false if it is/isn’t found. If you click on an accordion title, it will either add that unique accordion identifier to the array or remove it. Simple as that!

Demo

What’s next

In another post, we will take the above, functional accordion and create a new directive out of it. Directives are dynamic and powerful, so be sure to check out part two once it’s published!

Join the Conversation

8 Comments

  1. Do you have any sample code that can create the above from a dynamic List? I have been searching the web but all I can find are examples with static information. This is a great post nonetheless. Thanks for sharing your knowledge!

    1. Hey Bee,

      The example I used can definitely be tweaked to work with a dynamic list item. Are you looping through and generating the list yourself? If so, why not add the ng-click attributes like we are doing in the above static example?

      1. Hey Zach,
        Thank you soooo much for replying. The problem, in a nutshell, I’m working in Visual Studio 2013, the CSS was created by someone else and I have to keep the site consistent. The List is coming from a database through a repository. Currently, I am using a @foreach to loop through the list with a GroupBy clause for the group headers, and another @foreach to display the list. I can’t figure out how to use the code you supplied to make it work.

  2. This helped me out a lot. I did update it slightly to close other drawers when one is clicked:

    $scope.openTab = function (tab) {
    $scope.activeTabs.splice($scope.activeTabs.indexOf(tab), 1);
    //check if tab is already open
    if ($scope.isOpenTab(tab)) {
    //if it is, remove it from the activeTabs array
    $scope.activeTabs.splice($scope.activeTabs.indexOf(tab), 1);
    } else {
    //if it’s not, add it!
    $scope.activeTabs.push(tab);
    }
    }

    Thanks,
    Martin

    1. Hi Martin, your update looks nice but what if I click on the same tab and it should toggle too. Then how we need to do. There is no such example anywhere. If you can provide it will be good.

Leave a comment

Your email address will not be published. Required fields are marked *