Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow nested structure for accordions #25121

Merged
merged 8 commits into from
Dec 31, 2017
27 changes: 0 additions & 27 deletions docs/4.0/components/collapse.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,33 +113,6 @@ Using the [card]({{ site.baseurl }}/docs/{{ site.docs_version }}/components/card
</div>
{% endexample %}

You can also create accordions with custom markup. Add the `data-children` attribute and specify a set of sibling elements to toggle (e.g., `.item`). Then, use the same attributes and classes as shown above for connecting toggles to their associated content.

{% example html %}
<div id="exampleAccordion" data-children=".item">
<div class="item">
<a data-toggle="collapse" data-parent="#exampleAccordion" href="#exampleAccordion1" role="button" aria-expanded="true" aria-controls="exampleAccordion1">
Toggle item
</a>
<div id="exampleAccordion1" class="collapse show" role="tabpanel">
<p class="mb-3">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed pretium lorem non vestibulum scelerisque. Proin a vestibulum sem, eget tristique massa. Aliquam lacinia rhoncus nibh quis ornare.
</p>
</div>
</div>
<div class="item">
<a data-toggle="collapse" data-parent="#exampleAccordion" href="#exampleAccordion2" role="button" aria-expanded="false" aria-controls="exampleAccordion2">
Toggle item 2
</a>
<div id="exampleAccordion2" class="collapse" role="tabpanel">
<p class="mb-3">
Donec at ipsum dignissim, rutrum turpis scelerisque, tristique lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vivamus nec dui turpis. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.
</p>
</div>
</div>
</div>
{% endexample %}

## Accessibility

Be sure to add `aria-expanded` to the control element. This attribute explicitly conveys the current state of the collapsible element tied to the control to screen readers and similar assistive technologies. If the collapsible element is closed by default, the attribute on the control element should have a value of `aria-expanded="false"`. If you've set the collapsible element to be open by default using the `show` class, set `aria-expanded="true"` on the control instead. The plugin will automatically toggle this attribute on the control based on whether or not the collapsible element has been opened or closed (via JavaScript, or because the user triggered another control element also tied to the same collapsbile element). If the control element's HTML element is not a button (e.g., an `<a>` or `<div>`), the attribute `role="button"` should be added to the element.
Expand Down
6 changes: 5 additions & 1 deletion js/src/collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,11 @@ const Collapse = (($) => {
let activesData

if (this._parent) {
actives = $.makeArray($(this._parent).children().children(Selector.ACTIVES))
actives = $.makeArray(
$(this._parent)
.find(Selector.ACTIVES)
.filter(`[data-parent="${this._config.parent}"]`)
)
if (!actives.length) {
actives = null
}
Expand Down
58 changes: 48 additions & 10 deletions js/tests/unit/collapse.js
Original file line number Diff line number Diff line change
Expand Up @@ -516,12 +516,50 @@ $(function () {
var done = assert.async()
var accordionHTML = '<div id="accordion">'
+ '<div class="item">'
+ '<a id="linkTrigger" data-parent="#accordion" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree"></div>'
+ '<a id="linkTrigger" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion"></div>'
+ '</div>'
+ '<div class="item">'
+ '<a id="linkTriggerTwo" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>'
+ '<a id="linkTriggerTwo" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-parent="#accordion"></div>'
+ '</div>'
+ '</div>'

$(accordionHTML).appendTo('#qunit-fixture')
var $trigger = $('#linkTrigger')
var $triggerTwo = $('#linkTriggerTwo')
var $collapseOne = $('#collapseOne')
var $collapseTwo = $('#collapseTwo')
$collapseOne.on('shown.bs.collapse', function () {
assert.ok($collapseOne.hasClass('show'), '#collapseOne is shown')
assert.ok(!$collapseTwo.hasClass('show'), '#collapseTwo is not shown')
$collapseTwo.on('shown.bs.collapse', function () {
assert.ok(!$collapseOne.hasClass('show'), '#collapseOne is not shown')
assert.ok($collapseTwo.hasClass('show'), '#collapseTwo is shown')
done()
})
$triggerTwo.trigger($.Event('click'))
})
$trigger.trigger($.Event('click'))
})

QUnit.test('should allow accordion to contain nested elements', function (assert) {
assert.expect(4)
var done = assert.async()
var accordionHTML = '<div id="accordion">'
+ '<div class="row">'
+ '<div class="col-lg-6">'
+ '<div class="item">'
+ '<a id="linkTrigger" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree" data-parent="#accordion"></div>'
+ '</div>'
+ '</div>'
+ '<div class="col-lg-6">'
+ '<div class="item">'
+ '<a id="linkTriggerTwo" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo" data-parent="#accordion"></div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'

Expand All @@ -548,20 +586,20 @@ $(function () {
var done = assert.async()
$('<div id="accordion">'
+ '<div class="item">'
+ '<a id="linkTrigger" data-parent="#accordion" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree">'
+ '<a id="linkTrigger" data-toggle="collapse" href="#collapseOne" aria-expanded="false" aria-controls="collapseOne"></a>'
+ '<div id="collapseOne" data-parent="#accordion" class="collapse" role="tabpanel" aria-labelledby="headingThree">'
+ '<div id="nestedAccordion">'
+ '<div class="item">'
+ '<a id="nestedLinkTrigger" data-parent="#nestedAccordion" data-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>'
+ '<div id="nestedCollapseOne" class="collapse" role="tabpanel" aria-labelledby="headingThree">'
+ '<a id="nestedLinkTrigger" data-toggle="collapse" href="#nestedCollapseOne" aria-expanded="false" aria-controls="nestedCollapseOne"></a>'
+ '<div id="nestedCollapseOne" data-parent="#nestedAccordion" class="collapse" role="tabpanel" aria-labelledby="headingThree">'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '</div>'
+ '<div class="item">'
+ '<a id="linkTriggerTwo" data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>'
+ '<a id="linkTriggerTwo" data-toggle="collapse" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"></a>'
+ '<div id="collapseTwo" data-parent="#accordion" class="collapse show" role="tabpanel" aria-labelledby="headingTwo"></div>'
+ '</div>'
+ '</div>').appendTo('#qunit-fixture')
var $trigger = $('#linkTrigger')
Expand Down