AngularJS multi-level accordion
- Allows for a nested structure
- Works with (or without)
ng-repeat
- Allows multiple sections to be open at once
Demo
Usage
-
If you use bower or npm, just
bower/npm install v-accordion
. If not, download files from the github repo. -
Include
angular.js
,angular-animate.js
,v-accordion.js
, andv-accordion.css
:
<link href="v-accordion.css" rel="stylesheet" />
<script src="angular.js"></script>
<script src="angular-animate.js"></script>
<script src="v-accordion.js"></script>
- Add
vAccordion
as a dependency to your application module:
angular.module('myApp', ['vAccordion']);
- Put the following markup in your template:
<!-- add `multiple` attribute to allow multiple sections to open at once -->
<v-accordion class="vAccordion--default" multiple>
<!-- add expanded attribute to open the section -->
<v-pane expanded>
<v-pane-header>
Pane header #1
</v-pane-header>
<v-pane-content>
Pane content #1
</v-pane-content>
</v-pane>
<v-pane disabled>
<v-pane-header>
Pane header #2
</v-pane-header>
<v-pane-content>
Pane content #2
</v-pane-content>
</v-pane>
</v-accordion>
- You can also use
v-accordion
withng-repeat
:
<v-accordion class="vAccordion--default">
<v-pane ng-repeat="pane in panes" expanded="$first">
<v-pane-header>
{{ ::pane.header }}
</v-pane-header>
<v-pane-content>
{{ ::pane.content }}
<!-- accordions can be nested :) -->
<v-accordion ng-if="pane.subpanes">
<v-pane ng-repeat="subpane in pane.subpanes">
<v-pane-header>
{{ ::subpane.header }}
</v-pane-header>
<v-pane-content>
{{ ::subpane.content }}
</v-pane-content>
</v-pane>
</v-accordion>
</v-pane-content>
</v-pane>
</v-accordion>
API
Control
Add control
attribute and use following methods to control vAccordion from it's parent scope:
toggle(indexOrId)
expand(indexOrId)
collapse(indexOrId)
expandAll()
collapseAll()
hasExpandedPane()
<v-accordion id="my-accordion" multiple control="accordion">
<v-pane id="{{ pane.id }}" ng-repeat="pane in panes">
<v-pane-header>
{{ ::pane.header }}
</v-pane-header>
<v-pane-content>
{{ ::pane.content }}
</v-pane-content>
</v-pane>
</v-accordion>
<button ng-click="accordion.toggle(0)">Toggle first pane</button>
<button ng-click="accordion.expandAll()">Expand all</button>
<button ng-click="accordion.collapseAll()">Collapse all</button>
$scope.$on('my-accordion:onReady', function () {
var firstPane = $scope.panes[0];
$scope.accordion.toggle(firstPane.id);
});
Transcluded scope
$accordion
and $pane
scope properties allows you to control the directive from it's transcluded scope.
$accordion
toggle(indexOrId)
expand(indexOrId)
collapse(indexOrId)
expandAll()
collapseAll()
hasExpandedPane()
$pane
toggle()
expand()
collapse()
isExpanded()
<v-accordion multiple>
<v-pane ng-repeat="pane in panes">
<!-- here's how you can create a custom toggle button -->
<v-pane-header inactive>
{{ ::pane.header }}
<button ng-click="$pane.toggle()">Toggle me</button>
</v-pane-header>
<v-pane-content>
{{ ::pane.content }}
</v-pane-content>
</v-pane>
<button ng-click="$accordion.expandAll()">Expand all</button>
</v-accordion>
Events
vAccordion:onReady
oryourAccordionId:onReady
vAccordion:onExpand
oryourAccordionId:onExpand
vAccordion:onExpandAnimationEnd
oryourAccordionId:onExpandAnimationEnd
vAccordion:onCollapse
oryourAccordionId:onCollapse
vAccordion:onCollapseAnimationEnd
oryourAccordionId:onCollapseAnimationEnd
Callbacks
Use these callbacks to get expanded/collapsed pane index and id:
<v-accordion onexpand="expandCallback(index, id)" oncollapse="collapseCallback(index, id)">
<v-pane id="{{ ::pane.id }}" ng-repeat="pane in panes">
<v-pane-header>
{{ ::pane.header }}
</v-pane-header>
<v-pane-content>
{{ ::pane.content }}
</v-pane-content>
</v-pane>
</v-accordion>
$scope.expandCallback = function (index, id) {
console.log('expanded pane:', index, id);
};
$scope.collapseCallback = function (index, id) {
console.log('collapsed pane:', index, id));
};
Accessibility
vAccordion manages keyboard focus and adds some common aria-* attributes. BUT you should additionally place the aria-controls
and aria-labelledby
as follows:
<v-accordion>
<v-pane ng-repeat="pane in panes">
<v-pane-header id="{{ ::pane.id }}-header" aria-controls="{{ ::pane.id }}-content">
{{ ::pane.header }}
</v-pane-header>
<v-pane-content id="{{ ::pane.id }}-content" aria-labelledby="{{ ::pane.id }}-header">
{{ ::pane.content }}
</v-pane-content>
</v-pane>
</v-accordion>