]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
ARIA support for collapse
authorPatrick H. Lauke <redux@splintered.co.uk>
Tue, 15 Jul 2014 10:39:27 +0000 (11:39 +0100)
committerHeinrich Fenkart <hnrch02@gmail.com>
Mon, 8 Sep 2014 23:19:20 +0000 (01:19 +0200)
Added handling of aria-expanded=true/false to collapse.js, updated
documentation to include advice on making expand/collapse controls
accessible, updated examples and javascript documentation to use
aria-expanded and aria-controls (when targetting single collapsible
element, using ID rather than class selector)

Closes #14147.
Closes #14153.

14 files changed:
docs/_includes/js/collapse.html
docs/examples/carousel/index.html
docs/examples/dashboard/index.html
docs/examples/jumbotron/index.html
docs/examples/navbar-fixed-top/index.html
docs/examples/navbar-static-top/index.html
docs/examples/navbar/index.html
docs/examples/non-responsive/index.html
docs/examples/offcanvas/index.html
docs/examples/starter-template/index.html
docs/examples/sticky-footer-navbar/index.html
docs/examples/theme/index.html
js/collapse.js
js/tests/unit/collapse.js

index 4e7fb450a6b0d8b275e0d52e66388b16218ed60d..5239256a62012a69d9fccc9f505b0f8d1a637e9a 100644 (file)
@@ -17,7 +17,7 @@
       <div class="panel panel-default">
         <div class="panel-heading">
           <h4 class="panel-title">
-            <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
+            <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
               Collapsible Group Item #1
             </a>
           </h4>
@@ -31,7 +31,7 @@
       <div class="panel panel-default">
         <div class="panel-heading">
           <h4 class="panel-title">
-            <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo">
+            <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
               Collapsible Group Item #2
             </a>
           </h4>
@@ -45,7 +45,7 @@
       <div class="panel panel-default">
         <div class="panel-heading">
           <h4 class="panel-title">
-            <a data-toggle="collapse" data-parent="#accordion" href="#collapseThree">
+            <a data-toggle="collapse" data-parent="#accordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
               Collapsible Group Item #3
             </a>
           </h4>
@@ -63,7 +63,7 @@
   <div class="panel panel-default">
     <div class="panel-heading">
       <h4 class="panel-title">
-        <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne">
+        <a data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
           Collapsible Group Item #1
         </a>
       </h4>
@@ -77,7 +77,7 @@
   <div class="panel panel-default">
     <div class="panel-heading">
       <h4 class="panel-title">
-        <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo">
+        <a data-toggle="collapse" data-parent="#accordion" href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
           Collapsible Group Item #2
         </a>
       </h4>
@@ -91,7 +91,7 @@
   <div class="panel panel-default">
     <div class="panel-heading">
       <h4 class="panel-title">
-        <a data-toggle="collapse" data-parent="#accordion" href="#collapseThree">
+        <a data-toggle="collapse" data-parent="#accordion" href="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
           Collapsible Group Item #3
         </a>
       </h4>
 
   <p>You can also use the plugin without the accordion markup. Make a button toggle the expanding and collapsing of another element.</p>
 {% highlight html %}
-<button type="button" class="btn btn-danger" data-toggle="collapse" data-target="#demo">
+<button type="button" class="btn btn-danger" data-toggle="collapse" data-target="#demo" aria-expanded="true" aria-controls="demo">
   simple collapsible
 </button>
 
 <div id="demo" class="collapse in">...</div>
 {% endhighlight %}
 
+  <div class="bs-callout bs-callout-warning">
+    <h4>Make expand/collapse controls accessible</h4>
+    <p>Be sure to add <code>aria-expanded</code> to the control element. This attribute explicitly defines the current state of the collapsible element to screen readers and similar assistive technologies. If the collapsible element is closed by default, it should have a value of <code>aria-expanded="false"</code>. If you've set the collapsible element to be open by default using the <code>in</code> class, set <code>aria-expanded="true"</code> on the control instead. The plugin will automatically toggle this attribute based on whether or not the collapsible element has been opened or closed.</p>
+    <p>Additionally, if your control element is targetting a single collapsible element – i.e. the <code>data-target</code> attribute is pointing to an <code>id</code> selector – you may add an additional <code>aria-controls</code> attribute to the control element, containing the <code>id</code> of the collapsible element. Modern screen readers and similar assistive technologies make use of this attribute to provide users with additional shortcuts to navigate directly to the collapsible element itself.</p>
+  </div>
 
   <h2 id="collapse-usage">Usage</h2>
   <p>The collapse plugin utilizes a few classes to handle the heavy lifting:</p>
   <p>These classes can be found in <code>component-animations.less</code>.</p>
 
   <h3>Via data attributes</h3>
-  <p>Just add <code>data-toggle="collapse"</code> and a <code>data-target</code> to element to automatically assign control of a collapsible element. The <code>data-target</code> attribute accepts a CSS selector to apply the collapse to. Be sure to add the class <code>collapse</code> to the collapsible element. If you'd like it to default open, add the additional class <code>in</code>.</p>
+  <p>Just add <code>data-toggle="collapse"</code> and a <code>data-target</code> to the element to automatically assign control of a collapsible element. The <code>data-target</code> attribute accepts a CSS selector to apply the collapse to. Be sure to add the class <code>collapse</code> to the collapsible element. If you'd like it to default open, add the additional class <code>in</code>.</p>
   <p>To add accordion-like group management to a collapsible control, add the data attribute <code>data-parent="#selector"</code>. Refer to the demo to see this in action.</p>
 
   <h3>Via JavaScript</h3>
@@ -151,7 +156,7 @@ $('.collapse').collapse()
          <td>parent</td>
          <td>selector</td>
          <td>false</td>
-         <td>If selector then all collapsible elements under the specified parent will be closed when this collapsible item is shown. (similar to traditional accordion behavior - this dependent on the <code>panel</code> class)</td>
+         <td>If a selector is provided, then all collapsible elements under the specified parent will be closed when this collapsible item is shown. (similar to traditional accordion behavior - this is dependent on the <code>panel</code> class)</td>
        </tr>
        <tr>
          <td>toggle</td>
index 193a92657e28ea69ff91de76c910ef5eaa6712c1..3b185dcd92468069e18131ea095c070aaac0d7c7 100644 (file)
@@ -35,7 +35,7 @@
         <nav class="navbar navbar-inverse navbar-static-top" role="navigation">
           <div class="container">
             <div class="navbar-header">
-              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                 <span class="sr-only">Toggle navigation</span>
                 <span class="icon-bar"></span>
                 <span class="icon-bar"></span>
@@ -43,7 +43,7 @@
               </button>
               <a class="navbar-brand" href="#">Project name</a>
             </div>
-            <div class="navbar-collapse collapse">
+            <div id="navbar" class="navbar-collapse collapse">
               <ul class="nav navbar-nav">
                 <li class="active"><a href="#">Home</a></li>
                 <li><a href="#about">About</a></li>
index 6554d329be710b50712df0f15b4bb98d67693f0e..f69735da154e21aebc4b30cbea72daed4c91f5a2 100644 (file)
@@ -32,7 +32,7 @@
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
       <div class="container-fluid">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -40,7 +40,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="navbar-collapse collapse">
+        <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav navbar-right">
             <li><a href="#">Dashboard</a></li>
             <li><a href="#">Settings</a></li>
index 084dcfba135b284406766dccbbb7598c21a2f27e..81b8bfc4959eb87fedbcebb14a32011195465f13 100644 (file)
@@ -32,7 +32,7 @@
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -40,7 +40,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="navbar-collapse collapse">
+        <div id="navbar" class="navbar-collapse collapse">
           <form class="navbar-form navbar-right" role="form">
             <div class="form-group">
               <input type="text" placeholder="Email" class="form-control">
index 9d6fc3da3bb5d490e757618e3813197529a22f3e..09022528ce13ec3be9ec62ba0a094816b80d80d2 100644 (file)
@@ -33,7 +33,7 @@
     <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -41,7 +41,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="navbar-collapse collapse">
+        <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index 7bf0612a4cf30de690916f6815970e567c6c218e..77eba75edb61fb530405c946cdf92cba9fe91da4 100644 (file)
@@ -33,7 +33,7 @@
     <nav class="navbar navbar-default navbar-static-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -41,7 +41,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="navbar-collapse collapse">
+        <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index 18602664d45ab4012da9f62adb4bdd4fe678ac38..77e4c50cfe8a6393eee39b4ff5dbba1522d046ec 100644 (file)
@@ -35,7 +35,7 @@
       <nav class="navbar navbar-default" role="navigation">
         <div class="container-fluid">
           <div class="navbar-header">
-            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
               <span class="sr-only">Toggle navigation</span>
               <span class="icon-bar"></span>
               <span class="icon-bar"></span>
@@ -43,7 +43,7 @@
             </button>
             <a class="navbar-brand" href="#">Project name</a>
           </div>
-          <div class="navbar-collapse collapse">
+          <div id="navbar" class="navbar-collapse collapse">
             <ul class="nav navbar-nav">
               <li class="active"><a href="#">Link</a></li>
               <li><a href="#">Link</a></li>
index 9438a4079fc13ced4757e8dc46659c4c13f828c4..dd95192562fd4f4b56c097a98de7e6fcf96a3667 100644 (file)
@@ -35,7 +35,7 @@
     <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -43,7 +43,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="navbar-collapse collapse">
+        <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index aaf875ba24c652244d200dd01b3dd3cf26427807..74d249d95889263d1d4db6f3b4a95099f08a5f8c 100644 (file)
@@ -31,7 +31,7 @@
     <nav class="navbar navbar-fixed-top navbar-inverse" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -39,7 +39,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="collapse navbar-collapse">
+        <div id="navbar" class="collapse navbar-collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index 11b6c8c7b4214fa1622ae04895b337b3add245cd..ec4deb3914eb6d4d2390023727ceafc8280f904f 100644 (file)
@@ -32,7 +32,7 @@
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -40,7 +40,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="collapse navbar-collapse">
+        <div id="navbar" class="collapse navbar-collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index 5633ca21f0fc683b27a1acae714e05a0b07d72f0..2e596ccd22f2b2bd0d4cc1085b1bd973f78c9439 100644 (file)
@@ -33,7 +33,7 @@
     <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -41,7 +41,7 @@
           </button>
           <a class="navbar-brand" href="#">Project name</a>
         </div>
-        <div class="collapse navbar-collapse">
+        <div id="navbar" class="collapse navbar-collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index 8e8c72a1d9143fa00a2b2e3cb6343616c37937d0..16f4fa3e3ea10d1acf9d8877a16879441f9657bf 100644 (file)
@@ -35,7 +35,7 @@
     <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
       <div class="container">
         <div class="navbar-header">
-          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
             <span class="sr-only">Toggle navigation</span>
             <span class="icon-bar"></span>
             <span class="icon-bar"></span>
@@ -43,7 +43,7 @@
           </button>
           <a class="navbar-brand" href="#">Bootstrap theme</a>
         </div>
-        <div class="navbar-collapse collapse">
+        <div id="navbar" class="navbar-collapse collapse">
           <ul class="nav navbar-nav">
             <li class="active"><a href="#">Home</a></li>
             <li><a href="#about">About</a></li>
index f96be28607cf21ded2a0163a1173d6e01688775c..6a8377615e553824789dfad20b680c78b85445f4 100644 (file)
@@ -56,6 +56,7 @@
     this.$element
       .removeClass('collapse')
       .addClass('collapsing')[dimension](0)
+      .attr('aria-expanded', true)
 
     this.transitioning = 1
 
@@ -91,6 +92,7 @@
     this.$element
       .addClass('collapsing')
       .removeClass('collapse in')
+      .attr('aria-expanded', false)
 
     this.transitioning = 1
 
     var $parent = parent && $(parent)
 
     if (!data || !data.transitioning) {
-      if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed')
-      $this.toggleClass('collapsed', $target.hasClass('in'))
+      if ($parent) $parent.find('[data-toggle="collapse"][data-parent="' + parent + '"]').not($this).addClass('collapsed').attr('aria-expanded', false)
+      var isCollapsed = $target.hasClass('in')
+      $this.toggleClass('collapsed', isCollapsed).attr('aria-expanded', !isCollapsed)
     }
 
     Plugin.call($target, option)
index ffa8f7e6db803bc54c77cca4bf41dc9e2c473e3b..5d5849388c23949c6e02f11970314e83a00911b9 100644 (file)
@@ -75,7 +75,7 @@ $(function () {
   test('should remove "collapsed" class from target when collapse is shown', function () {
     stop()
 
-    var $target = $('<a data-toggle="collapse" href="#test1"/>').appendTo('#qunit-fixture')
+    var $target = $('<a data-toggle="collapse" class="collapsed" href="#test1"/>').appendTo('#qunit-fixture')
 
     $('<div id="test1"/>')
       .appendTo('#qunit-fixture')
@@ -200,4 +200,67 @@ $(function () {
     $target3.click()
   })
 
-})
+  test('should set aria-expanded="true" on target when collapse is shown', function () {
+    stop()
+
+    var $target = $('<a data-toggle="collapse" class="collapsed" href="#test1" aria-expanded="false"/>').appendTo('#qunit-fixture')
+
+    $('<div id="test1"/>')
+      .appendTo('#qunit-fixture')
+      .on('show.bs.collapse', function () {
+        equal($target.attr('aria-expanded'), 'true', 'aria-expanded on target is "true"')
+        start()
+      })
+
+    $target.click()
+  })
+
+  test('should set aria-expanded="false" on target when collapse is hidden', function () {
+    stop()
+
+    var $target = $('<a data-toggle="collapse" href="#test1" aria-expanded="true"/>').appendTo('#qunit-fixture')
+
+    $('<div id="test1" class="in"/>')
+      .appendTo('#qunit-fixture')
+      .on('hide.bs.collapse', function () {
+        equal($target.attr('aria-expanded'), 'false', 'aria-expanded on target is "false"')
+        start()
+      })
+
+    $target.click()
+  })
+
+  test('should change aria-expanded from active accordion target to "false" and set the newly active one to "true"', function () {
+    stop()
+
+    var accordionHTML = '<div id="accordion">'
+        + '<div class="accordion-group"/>'
+        + '<div class="accordion-group"/>'
+        + '<div class="accordion-group"/>'
+        + '</div>'
+    var $groups = $(accordionHTML).appendTo('#qunit-fixture').find('.accordion-group')
+
+    var $target1 = $('<a data-toggle="collapse" href="#body1" data-parent="#accordion"/>').appendTo($groups.eq(0))
+
+    $('<div id="body1" aria-expanded="true" class="in"/>').appendTo($groups.eq(0))
+
+    var $target2 = $('<a class="collapsed" data-toggle="collapse" href="#body2" data-parent="#accordion"/>').appendTo($groups.eq(1))
+
+    $('<div id="body2" aria-expanded="false"/>').appendTo($groups.eq(1))
+
+    var $target3 = $('<a class="collapsed" data-toggle="collapse" href="#body3" data-parent="#accordion"/>').appendTo($groups.eq(2))
+
+    $('<div id="body3" aria-expanded="false"/>')
+      .appendTo($groups.eq(2))
+      .on('show.bs.collapse', function () {
+        equal($target1.attr('aria-expanded'), 'false', 'inactive target 1 has aria-expanded="false"')
+        equal($target2.attr('aria-expanded'), 'false', 'inactive target 2 has aria-expanded="false"')
+        equal($target3.attr('aria-expanded'), 'true', 'active target 3 has aria-expanded="false"')
+
+        start()
+      })
+
+    $target3.click()
+  })
+
+})
\ No newline at end of file