Skip to content

Commit

Permalink
Backport #30936
Browse files Browse the repository at this point in the history
Add role="dialog" in modals via JavaScript
  • Loading branch information
XhmikosR committed Jun 4, 2020
1 parent 2d39ef6 commit fb93c92
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 22 deletions.
2 changes: 2 additions & 0 deletions js/src/modal.js
Expand Up @@ -265,6 +265,7 @@ class Modal {
this._element.style.display = 'block'
this._element.removeAttribute('aria-hidden')
this._element.setAttribute('aria-modal', true)
this._element.setAttribute('role', 'dialog')

if ($(this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) {
modalBody.scrollTop = 0
Expand Down Expand Up @@ -344,6 +345,7 @@ class Modal {
this._element.style.display = 'none'
this._element.setAttribute('aria-hidden', true)
this._element.removeAttribute('aria-modal')
this._element.removeAttribute('role')
this._isTransitioning = false
this._showBackdrop(() => {
$(document.body).removeClass(CLASS_NAME_OPEN)
Expand Down
17 changes: 17 additions & 0 deletions js/tests/unit/modal.js
Expand Up @@ -297,6 +297,23 @@ $(function () {
.bootstrapModal('show')
})

QUnit.test('should add role="dialog" attribute when shown, remove it again when hidden', function (assert) {
assert.expect(3)
var done = assert.async()

$('<div id="modal-test"/>')
.on('shown.bs.modal', function () {
assert.ok($('#modal-test').is('[role]'), 'role attribute added')
assert.strictEqual($('#modal-test').attr('role'), 'dialog', 'correct role="dialog" added')
$(this).bootstrapModal('hide')
})
.on('hidden.bs.modal', function () {
assert.notOk($('#modal-test').is('[role]'), 'role attribute removed')
done()
})
.bootstrapModal('show')
})

QUnit.test('should close reopened modal with [data-dismiss="modal"] click', function (assert) {
assert.expect(2)
var done = assert.async()
Expand Down
8 changes: 4 additions & 4 deletions js/tests/visual/modal.html
Expand Up @@ -34,7 +34,7 @@
<div class="container mt-3">
<h1>Modal <small>Bootstrap Visual Test</small></h1>

<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal fade" id="myModal" tabindex="-1" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -121,7 +121,7 @@ <h4>Overflowing text to show scroll behavior</h4>
</div>
</div>

<div class="modal fade" id="firefoxModal" tabindex="-1" role="dialog" aria-labelledby="firefoxModalLabel" aria-hidden="true">
<div class="modal fade" id="firefoxModal" tabindex="-1" aria-labelledby="firefoxModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -147,7 +147,7 @@ <h4 class="modal-title" id="firefoxModalLabel">Firefox Bug Test</h4>
</div>
</div>

<div class="modal fade" id="slowModal" tabindex="-1" role="dialog" aria-labelledby="slowModalLabel" aria-hidden="true" style="transition-duration: 5s;">
<div class="modal fade" id="slowModal" tabindex="-1" aria-labelledby="slowModalLabel" aria-hidden="true" style="transition-duration: 5s;">
<div class="modal-dialog" style="transition-duration: inherit;">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -194,7 +194,7 @@ <h4 class="modal-title" id="slowModalLabel">Lorem slowly</h4>
Tall body content to force the page to have a scrollbar.
</div>

<button type="button" class="btn btn-secondary btn-lg" data-toggle="modal" data-target="&#x3C;div class=&#x22;modal fade the-bad&#x22; tabindex=&#x22;-1&#x22; role=&#x22;dialog&#x22;&#x3E;&#x3C;div class=&#x22;modal-dialog&#x22; role=&#x22;document&#x22;&#x3E;&#x3C;div class=&#x22;modal-content&#x22;&#x3E;&#x3C;div class=&#x22;modal-header&#x22;&#x3E;&#x3C;button type=&#x22;button&#x22; class=&#x22;close&#x22; data-dismiss=&#x22;modal&#x22; aria-label=&#x22;Close&#x22;&#x3E;&#x3C;span aria-hidden=&#x22;true&#x22;&#x3E;&#x26;times;&#x3C;/span&#x3E;&#x3C;/button&#x3E;&#x3C;h4 class=&#x22;modal-title&#x22;&#x3E;The Bad Modal&#x3C;/h4&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;modal-body&#x22;&#x3E;This modal&#x27;s HTTML source code is declared inline, inside the data-target attribute of it&#x27;s show-button&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;">
<button type="button" class="btn btn-secondary btn-lg" data-toggle="modal" data-target="&#x3C;div class=&#x22;modal fade the-bad&#x22; tabindex=&#x22;-1&#x22;&#x3E;&#x3C;div class=&#x22;modal-dialog&#x22;&#x3E;&#x3C;div class=&#x22;modal-content&#x22;&#x3E;&#x3C;div class=&#x22;modal-header&#x22;&#x3E;&#x3C;button type=&#x22;button&#x22; class=&#x22;close&#x22; data-dismiss=&#x22;modal&#x22; aria-label=&#x22;Close&#x22;&#x3E;&#x3C;span aria-hidden=&#x22;true&#x22;&#x3E;&#x26;times;&#x3C;/span&#x3E;&#x3C;/button&#x3E;&#x3C;h4 class=&#x22;modal-title&#x22;&#x3E;The Bad Modal&#x3C;/h4&#x3E;&#x3C;/div&#x3E;&#x3C;div class=&#x22;modal-body&#x22;&#x3E;This modal&#x27;s HTTML source code is declared inline, inside the data-target attribute of it&#x27;s show-button&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;&#x3C;/div&#x3E;">
Modal with an XSS inside the data-target
</button>

Expand Down
36 changes: 18 additions & 18 deletions site/docs/4.5/components/modal.md
Expand Up @@ -34,7 +34,7 @@ Keep reading for demos and usage guidelines.
Below is a _static_ modal example (meaning its `position` and `display` have been overridden). Included are the modal header, modal body (required for `padding`), and modal footer (optional). We ask that you include modal headers with dismiss actions whenever possible, or provide another explicit dismiss action.

<div class="bd-example bd-example-modal">
<div class="modal" tabindex="-1" role="dialog">
<div class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -56,7 +56,7 @@ Below is a _static_ modal example (meaning its `position` and `display` have bee
</div>

{% highlight html %}
<div class="modal" tabindex="-1" role="dialog">
<div class="modal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -81,7 +81,7 @@ Below is a _static_ modal example (meaning its `position` and `display` have bee

Toggle a working modal demo by clicking the button below. It will slide down and fade in from the top of the page.

<div class="modal fade" id="exampleModalLive" tabindex="-1" role="dialog" aria-labelledby="exampleModalLiveLabel" aria-hidden="true">
<div class="modal fade" id="exampleModalLive" tabindex="-1" aria-labelledby="exampleModalLiveLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -114,7 +114,7 @@ Toggle a working modal demo by clicking the button below. It will slide down and
</button>

<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -139,7 +139,7 @@ Toggle a working modal demo by clicking the button below. It will slide down and

When backdrop is set to static, the modal will not close when clicking outside it. Click the button below to try it.

<div class="modal fade" id="staticBackdropLive" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLiveLabel" aria-hidden="true">
<div class="modal fade" id="staticBackdropLive" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLiveLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -172,7 +172,7 @@ When backdrop is set to static, the modal will not close when clicking outside i
</button>

<!-- Modal -->
<div class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal fade" id="staticBackdrop" data-backdrop="static" data-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -198,7 +198,7 @@ When backdrop is set to static, the modal will not close when clicking outside i

When modals become too long for the user's viewport or device, they scroll independent of the page itself. Try the demo below to see what we mean.

<div class="modal fade" id="exampleModalLong" tabindex="-1" role="dialog" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal fade" id="exampleModalLong" tabindex="-1" aria-labelledby="exampleModalLongTitle" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -243,7 +243,7 @@ When modals become too long for the user's viewport or device, they scroll indep

You can also create a scrollable modal that allows scroll the modal body by adding `.modal-dialog-scrollable` to `.modal-dialog`.

<div class="modal fade" id="exampleModalScrollable" tabindex="-1" role="dialog" aria-labelledby="exampleModalScrollableTitle" aria-hidden="true">
<div class="modal fade" id="exampleModalScrollable" tabindex="-1" aria-labelledby="exampleModalScrollableTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -297,7 +297,7 @@ You can also create a scrollable modal that allows scroll the modal body by addi

Add `.modal-dialog-centered` to `.modal-dialog` to vertically center the modal.

<div class="modal fade" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal fade" id="exampleModalCenter" tabindex="-1" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
Expand All @@ -317,7 +317,7 @@ Add `.modal-dialog-centered` to `.modal-dialog` to vertically center the modal.
</div>
</div>

<div class="modal fade" id="exampleModalCenteredScrollable" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenteredScrollableTitle" aria-hidden="true">
<div class="modal fade" id="exampleModalCenteredScrollable" tabindex="-1" aria-labelledby="exampleModalCenteredScrollableTitle" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -366,7 +366,7 @@ Add `.modal-dialog-centered` to `.modal-dialog` to vertically center the modal.

[Tooltips]({{ site.baseurl }}/docs/{{ site.docs_version }}/components/tooltips/) and [popovers]({{ site.baseurl }}/docs/{{ site.docs_version }}/components/popovers/) can be placed within modals as needed. When modals are closed, any tooltips and popovers within are also automatically dismissed.

<div class="modal fade" id="exampleModalPopovers" tabindex="-1" role="dialog" aria-labelledby="exampleModalPopoversLabel" aria-hidden="true">
<div class="modal fade" id="exampleModalPopovers" tabindex="-1" aria-labelledby="exampleModalPopoversLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -410,7 +410,7 @@ Add `.modal-dialog-centered` to `.modal-dialog` to vertically center the modal.

Utilize the Bootstrap grid system within a modal by nesting `.container-fluid` within the `.modal-body`. Then, use the normal grid system classes as you would anywhere else.

<div class="modal fade" id="gridSystemModal" tabindex="-1" role="dialog" aria-labelledby="gridModalLabel" aria-hidden="true">
<div class="modal fade" id="gridSystemModal" tabindex="-1" aria-labelledby="gridModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -501,7 +501,7 @@ Below is a live demo followed by example HTML and JavaScript. For more informati
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@fat">Open modal for @fat</button>
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal" data-whatever="@getbootstrap">Open modal for @getbootstrap</button>

<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
Expand Down Expand Up @@ -555,7 +555,7 @@ If you want for example a zoom-in animation, you can set `$modal-fade-transform:
For modals that simply appear rather than fade in to view, remove the `.fade` class from your modal markup.

{% highlight html %}
<div class="modal" tabindex="-1" role="dialog" aria-labelledby="..." aria-hidden="true">
<div class="modal" tabindex="-1" aria-labelledby="..." aria-hidden="true">
...
</div>
{% endhighlight %}
Expand All @@ -566,7 +566,7 @@ If the height of a modal changes while it is open, you should call `$('#myModal'

### Accessibility

Be sure to add `role="dialog"` and `aria-labelledby="..."`, referencing the modal title, to `.modal`. Additionally, you may give a description of your modal dialog with `aria-describedby` on `.modal`.
Be sure to add `aria-labelledby="..."`, referencing the modal title, to `.modal`. Additionally, you may give a description of your modal dialog with `aria-describedby` on `.modal`. Note that you don't need to add `role="dialog"` since we already add it via JavaScript.

### Embedding YouTube videos

Expand Down Expand Up @@ -622,7 +622,7 @@ Our default modal without modifier class constitutes the "medium" size modal.
<div class="modal-dialog modal-sm">...</div>
{% endhighlight %}

<div class="modal fade" id="exampleModalXl" tabindex="-1" role="dialog" aria-labelledby="exampleModalXlLabel" aria-hidden="true">
<div class="modal fade" id="exampleModalXl" tabindex="-1" aria-labelledby="exampleModalXlLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">

Expand All @@ -639,7 +639,7 @@ Our default modal without modifier class constitutes the "medium" size modal.
</div>
</div>

<div class="modal fade" id="exampleModalLg" tabindex="-1" role="dialog" aria-labelledby="exampleModalLgLabel" aria-hidden="true">
<div class="modal fade" id="exampleModalLg" tabindex="-1" aria-labelledby="exampleModalLgLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">

Expand All @@ -656,7 +656,7 @@ Our default modal without modifier class constitutes the "medium" size modal.
</div>
</div>

<div class="modal fade" id="exampleModalSm" tabindex="-1" role="dialog" aria-labelledby="exampleModalSmLabel" aria-hidden="true">
<div class="modal fade" id="exampleModalSm" tabindex="-1" aria-labelledby="exampleModalSmLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
Expand Down

0 comments on commit fb93c92

Please sign in to comment.