mirror of
https://github.com/twbs/bootstrap.git
synced 2024-11-28 10:24:19 +01:00
Dynamic tabs: use buttons rather than links (backport to v4) (#33163)
* Manually backport 32630 Dynamic tabs: use buttons rather than links * Tweak unit test * Tweak unit tests * More tweakage * show() should also bail if `disabled` attribute is set * Tweak tests * Simplify test for relatedTarget * Temporarily remove problematic test (as i can't get local tests to run just noww) * Revert previous * test: fix broken test cases for tab.js * test: fix role=tablist invalid on nav element * test: prefer <div/> over <div></div> * Manually backport 32630 Dynamic tabs: use buttons rather than links * test: fix broken test cases for tab.js * Fixes * Remove and ignore lock file Co-authored-by: alpadev <alpa.muc@gmail.com> Co-authored-by: Mark Otto <markd.otto@gmail.com> Co-authored-by: Mark Otto <markdotto@gmail.com>
This commit is contained in:
parent
e4dc2e91a5
commit
7d57d9a68b
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,7 +1,8 @@
|
|||||||
# Ignore docs files
|
# Ignore docs files
|
||||||
/_site/
|
/_site/
|
||||||
# Hugo folders
|
# Hugo files
|
||||||
/resources/
|
/resources/
|
||||||
|
/.hugo_build.lock
|
||||||
|
|
||||||
# Numerous always-ignore extensions
|
# Numerous always-ignore extensions
|
||||||
*.diff
|
*.diff
|
||||||
|
@ -58,7 +58,8 @@ class Tab {
|
|||||||
if (this._element.parentNode &&
|
if (this._element.parentNode &&
|
||||||
this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
|
this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
|
||||||
$(this._element).hasClass(CLASS_NAME_ACTIVE) ||
|
$(this._element).hasClass(CLASS_NAME_ACTIVE) ||
|
||||||
$(this._element).hasClass(CLASS_NAME_DISABLED)) {
|
$(this._element).hasClass(CLASS_NAME_DISABLED) ||
|
||||||
|
this._element.hasAttribute('disabled')) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,14 +44,30 @@ $(function () {
|
|||||||
assert.strictEqual($tab[0], $el[0], 'collection contains element')
|
assert.strictEqual($tab[0], $el[0], 'collection contains element')
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('should activate element by tab id', function (assert) {
|
QUnit.test('should activate element by tab id (using buttons, the preferred semantic way)', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var tabsHTML = '<ul class="nav">' +
|
var tabsHTML = '<ul class="nav" role="tablist">' +
|
||||||
'<li><a href="#home">Home</a></li>' +
|
'<li><button type="button" data-target="#home" role="tab">Home</button></li>' +
|
||||||
'<li><a href="#profile">Profile</a></li>' +
|
'<li><button type="button" data-target="#profile" role="tab">Profile</button></li>' +
|
||||||
'</ul>'
|
'</ul>'
|
||||||
|
|
||||||
$('<ul><li id="home"/><li id="profile"/></ul>').appendTo('#qunit-fixture')
|
$('<ul><li id="home" role="tabpanel"></li><li id="profile" role="tabpanel"></li></ul>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
|
$(tabsHTML).find('li:last-child button').bootstrapTab('show')
|
||||||
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
||||||
|
|
||||||
|
$(tabsHTML).find('li:first-child button').bootstrapTab('show')
|
||||||
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
||||||
|
})
|
||||||
|
|
||||||
|
QUnit.test('should activate element by tab id (using links for tabs - not ideal, but still supported)', function (assert) {
|
||||||
|
assert.expect(2)
|
||||||
|
var tabsHTML = '<ul class="nav" role="tablist">' +
|
||||||
|
'<li><a href="#home" role="tab">Home</a></li>' +
|
||||||
|
'<li><a href="#profile" role="tab">Profile</a></li>' +
|
||||||
|
'</ul>'
|
||||||
|
|
||||||
|
$('<ul><li id="home" role="tabpanel"/><li id="profile" role="tabpanel"/></ul>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
$(tabsHTML).find('li:last-child a').bootstrapTab('show')
|
$(tabsHTML).find('li:last-child a').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
||||||
@ -79,48 +95,48 @@ $(function () {
|
|||||||
QUnit.test('should activate element by tab id in ordered list', function (assert) {
|
QUnit.test('should activate element by tab id in ordered list', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var pillsHTML = '<ol class="nav nav-pills">' +
|
var pillsHTML = '<ol class="nav nav-pills">' +
|
||||||
'<li><a href="#home">Home</a></li>' +
|
'<li><button type="button" data-target="#home" role="tab">Home</button></li>' +
|
||||||
'<li><a href="#profile">Profile</a></li>' +
|
'<li><button type="button" href="#profile" role="tab">Profile</button></li>' +
|
||||||
'</ol>'
|
'</ol>'
|
||||||
|
|
||||||
$('<ol><li id="home"/><li id="profile"/></ol>').appendTo('#qunit-fixture')
|
$('<ol><li id="home" role="tabpanel"/><li id="profile" role="tabpanel"/></ol>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
$(pillsHTML).find('li:last-child a').bootstrapTab('show')
|
$(pillsHTML).find('li:last-child button').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
||||||
|
|
||||||
$(pillsHTML).find('li:first-child a').bootstrapTab('show')
|
$(pillsHTML).find('li:first-child button').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('should activate element by tab id in nav list', function (assert) {
|
QUnit.test('should activate element by tab id in nav list', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var tabsHTML = '<nav class="nav">' +
|
var tabsHTML = '<nav class="nav">' +
|
||||||
'<a href="#home">Home</a>' +
|
'<button type="button" data-target="#home" role="tab">Home</button>' +
|
||||||
'<a href="#profile">Profile</a>' +
|
'<button type="button" data-target="#profile" role="tab">Profile</a>' +
|
||||||
'</nav>'
|
'</nav>'
|
||||||
|
|
||||||
$('<nav><div id="home"></div><div id="profile"></div></nav>').appendTo('#qunit-fixture')
|
$('<div><div id="home" role="tabpanel"/><div id="profile" role="tabpanel"/></div>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
$(tabsHTML).find('a:last-child').bootstrapTab('show')
|
$(tabsHTML).find('button:last-child').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
||||||
|
|
||||||
$(tabsHTML).find('a:first-child').bootstrapTab('show')
|
$(tabsHTML).find('button:first-child').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('should activate element by tab id in list group', function (assert) {
|
QUnit.test('should activate element by tab id in list group', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var tabsHTML = '<div class="list-group">' +
|
var tabsHTML = '<div class="list-group" role="tablist">' +
|
||||||
'<a href="#home">Home</a>' +
|
'<button type="button" data-target="#home" role="tab">Home</button>' +
|
||||||
'<a href="#profile">Profile</a>' +
|
'<button type="button" data-target="#profile" role="tab">Profile</button>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
|
|
||||||
$('<nav><div id="home"></div><div id="profile"></div></nav>').appendTo('#qunit-fixture')
|
$('<div><div id="home" role="tabpanel"/><div id="profile" role="tabpanel"/></div>').appendTo('#qunit-fixture')
|
||||||
|
|
||||||
$(tabsHTML).find('a:last-child').bootstrapTab('show')
|
$(tabsHTML).find('button:last-child').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'profile')
|
||||||
|
|
||||||
$(tabsHTML).find('a:first-child').bootstrapTab('show')
|
$(tabsHTML).find('button:first-child').bootstrapTab('show')
|
||||||
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
assert.strictEqual($('#qunit-fixture').find('.active').attr('id'), 'home')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -143,8 +159,8 @@ $(function () {
|
|||||||
QUnit.test('should not fire shown when tab is already active', function (assert) {
|
QUnit.test('should not fire shown when tab is already active', function (assert) {
|
||||||
assert.expect(0)
|
assert.expect(0)
|
||||||
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
||||||
'<li class="nav-item" role="presentation"><a href="#home" class="nav-link active" role="tab">Home</a></li>' +
|
'<li class="nav-item" role="presentation"><button type="button" data-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>' +
|
||||||
'<li class="nav-item" role="presentation"><a href="#profile" class="nav-link" role="tab">Profile</a></li>' +
|
'<li class="nav-item" role="presentation"><button type="button" data-target="#profile" class="nav-link" role="tab">Profile</button></li>' +
|
||||||
'</ul>' +
|
'</ul>' +
|
||||||
'<div class="tab-content">' +
|
'<div class="tab-content">' +
|
||||||
'<div class="tab-pane active" id="home" role="tabpanel"></div>' +
|
'<div class="tab-pane active" id="home" role="tabpanel"></div>' +
|
||||||
@ -152,7 +168,7 @@ $(function () {
|
|||||||
'</div>'
|
'</div>'
|
||||||
|
|
||||||
$(tabsHTML)
|
$(tabsHTML)
|
||||||
.find('a.active')
|
.find('button.active')
|
||||||
.on('shown.bs.tab', function () {
|
.on('shown.bs.tab', function () {
|
||||||
assert.ok(true, 'shown event fired')
|
assert.ok(true, 'shown event fired')
|
||||||
})
|
})
|
||||||
@ -162,8 +178,8 @@ $(function () {
|
|||||||
QUnit.test('should not fire shown when tab is disabled', function (assert) {
|
QUnit.test('should not fire shown when tab is disabled', function (assert) {
|
||||||
assert.expect(0)
|
assert.expect(0)
|
||||||
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
||||||
'<li class="nav-item"><a href="#home" class="nav-link active" role="tab">Home</a></li>' +
|
'<li class="nav-item"><button type="button" data-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>' +
|
||||||
'<li class="nav-item"><a href="#profile" class="nav-link disabled" role="tab">Profile</a></li>' +
|
'<li class="nav-item"><button type="button" data-target="#profile" class="nav-link" disabled role="tab">Profile</button></li>' +
|
||||||
'</ul>' +
|
'</ul>' +
|
||||||
'<div class="tab-content">' +
|
'<div class="tab-content">' +
|
||||||
'<div class="tab-pane active" id="home" role="tabpanel"></div>' +
|
'<div class="tab-pane active" id="home" role="tabpanel"></div>' +
|
||||||
@ -171,7 +187,7 @@ $(function () {
|
|||||||
'</div>'
|
'</div>'
|
||||||
|
|
||||||
$(tabsHTML)
|
$(tabsHTML)
|
||||||
.find('a.disabled')
|
.find('button[disabled]')
|
||||||
.on('shown.bs.tab', function () {
|
.on('shown.bs.tab', function () {
|
||||||
assert.ok(true, 'shown event fired')
|
assert.ok(true, 'shown event fired')
|
||||||
})
|
})
|
||||||
@ -182,26 +198,23 @@ $(function () {
|
|||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var done = assert.async()
|
var done = assert.async()
|
||||||
|
|
||||||
var dropHTML =
|
var tabsHTML =
|
||||||
'<ul class="drop nav">' +
|
'<ul class="nav nav-tabs" role="tablist">' +
|
||||||
' <li class="dropdown"><a data-toggle="dropdown" href="#">1</a>' +
|
' <li class="nav-item" role="presentation"><button type="button" data-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>' +
|
||||||
' <ul class="dropdown-menu nav">' +
|
' <li class="nav-item" role="presentation"><button type="button" data-target="#profile" class="nav-link" role="tab" aria-selected="false">Profile</button></li>' +
|
||||||
' <li><a href="#a1-1" data-toggle="tab">1-1</a></li>' +
|
|
||||||
' <li><a href="#a1-2" data-toggle="tab">1-2</a></li>' +
|
|
||||||
'</ul>' +
|
'</ul>' +
|
||||||
' </li>' +
|
'<div class="tab-content">' +
|
||||||
'</ul>'
|
' <div class="tab-pane active" id="home" role="tabpanel"/>' +
|
||||||
|
' <div class="tab-pane" id="profile" role="tabpanel"/>' +
|
||||||
|
'</div>'
|
||||||
|
|
||||||
$(dropHTML)
|
$(tabsHTML)
|
||||||
.find('ul > li:first-child a')
|
.find('li:last-child button')
|
||||||
.bootstrapTab('show')
|
|
||||||
.end()
|
|
||||||
.find('ul > li:last-child a')
|
|
||||||
.on('show.bs.tab', function (e) {
|
.on('show.bs.tab', function (e) {
|
||||||
assert.strictEqual(e.relatedTarget.hash, '#a1-1', 'references correct element as relatedTarget')
|
assert.strictEqual(e.relatedTarget.getAttribute('data-target'), '#home', 'references correct element as relatedTarget')
|
||||||
})
|
})
|
||||||
.on('shown.bs.tab', function (e) {
|
.on('shown.bs.tab', function (e) {
|
||||||
assert.strictEqual(e.relatedTarget.hash, '#a1-1', 'references correct element as relatedTarget')
|
assert.strictEqual(e.relatedTarget.getAttribute('data-target'), '#home', 'references correct element as relatedTarget')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
@ -211,30 +224,30 @@ $(function () {
|
|||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var done = assert.async()
|
var done = assert.async()
|
||||||
|
|
||||||
var tabsHTML = '<ul class="nav">' +
|
var tabsHTML = '<ul class="nav" role="tablist">' +
|
||||||
'<li><a href="#home">Home</a></li>' +
|
'<li><button type="button" data-target="#home" role="tab">Home</button></li>' +
|
||||||
'<li><a href="#profile">Profile</a></li>' +
|
'<li><button type="button" data-target="#profile">Profile</button></li>' +
|
||||||
'</ul>'
|
'</ul>'
|
||||||
|
|
||||||
$(tabsHTML)
|
$(tabsHTML)
|
||||||
.find('li:first-child a')
|
.find('li:first-child button')
|
||||||
.on('hide.bs.tab', function () {
|
.on('hide.bs.tab', function () {
|
||||||
assert.ok(true, 'hide event fired')
|
assert.ok(true, 'hide event fired')
|
||||||
})
|
})
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
.end()
|
.end()
|
||||||
.find('li:last-child a')
|
.find('li:last-child button')
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
|
|
||||||
$(tabsHTML)
|
$(tabsHTML)
|
||||||
.find('li:first-child a')
|
.find('li:first-child button')
|
||||||
.on('hidden.bs.tab', function () {
|
.on('hidden.bs.tab', function () {
|
||||||
assert.ok(true, 'hidden event fired')
|
assert.ok(true, 'hidden event fired')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
.end()
|
.end()
|
||||||
.find('li:last-child a')
|
.find('li:last-child button')
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -242,13 +255,13 @@ $(function () {
|
|||||||
assert.expect(1)
|
assert.expect(1)
|
||||||
var done = assert.async()
|
var done = assert.async()
|
||||||
|
|
||||||
var tabsHTML = '<ul class="nav">' +
|
var tabsHTML = '<ul class="nav" role="tablist">' +
|
||||||
'<li><a href="#home">Home</a></li>' +
|
'<li><button type="button" data-target="#home" role="tab">Home</button></li>' +
|
||||||
'<li><a href="#profile">Profile</a></li>' +
|
'<li><button type="button" data-target="#profile" role="tab">Profile</button></li>' +
|
||||||
'</ul>'
|
'</ul>'
|
||||||
|
|
||||||
$(tabsHTML)
|
$(tabsHTML)
|
||||||
.find('li:first-child a')
|
.find('li:first-child button')
|
||||||
.on('hide.bs.tab', function (e) {
|
.on('hide.bs.tab', function (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
assert.ok(true, 'hide event fired')
|
assert.ok(true, 'hide event fired')
|
||||||
@ -259,7 +272,7 @@ $(function () {
|
|||||||
})
|
})
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
.end()
|
.end()
|
||||||
.find('li:last-child a')
|
.find('li:last-child button')
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -267,82 +280,62 @@ $(function () {
|
|||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var done = assert.async()
|
var done = assert.async()
|
||||||
|
|
||||||
var tabsHTML = '<ul class="nav">' +
|
var tabsHTML = '<ul class="nav" role="tablist">' +
|
||||||
'<li><a href="#home">Home</a></li>' +
|
'<li><button type="button" data-target="#home" role="tab">Home</button></li>' +
|
||||||
'<li><a href="#profile">Profile</a></li>' +
|
'<li><button type="button" data-target="#profile" role="tab">Profile</button></li>' +
|
||||||
'</ul>'
|
'</ul>'
|
||||||
|
|
||||||
$(tabsHTML)
|
$(tabsHTML)
|
||||||
.find('li:first-child a')
|
.find('li:first-child button')
|
||||||
.on('hide.bs.tab', function (e) {
|
.on('hide.bs.tab', function (e) {
|
||||||
assert.strictEqual(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget')
|
assert.strictEqual(e.relatedTarget.getAttribute('data-target'), '#profile', 'references correct element as relatedTarget')
|
||||||
})
|
})
|
||||||
.on('hidden.bs.tab', function (e) {
|
.on('hidden.bs.tab', function (e) {
|
||||||
assert.strictEqual(e.relatedTarget.hash, '#profile', 'references correct element as relatedTarget')
|
assert.strictEqual(e.relatedTarget.getAttribute('data-target'), '#profile', 'references correct element as relatedTarget')
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
.end()
|
.end()
|
||||||
.find('li:last-child a')
|
.find('li:last-child button')
|
||||||
.bootstrapTab('show')
|
.bootstrapTab('show')
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('selected tab should have aria-selected', function (assert) {
|
QUnit.test('selected tab should have correct aria-selected', function (assert) {
|
||||||
assert.expect(8)
|
assert.expect(8)
|
||||||
var tabsHTML = '<ul class="nav nav-tabs">' +
|
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
||||||
'<li><a class="nav-item active" href="#home" toggle="tab" aria-selected="true">Home</a></li>' +
|
'<li><button type="button" data-target="#home" role="tab" aria-selected="false">Home</button></li>' +
|
||||||
'<li><a class="nav-item" href="#profile" toggle="tab" aria-selected="false">Profile</a></li>' +
|
'<li><button type="button" data-target="#profile" role="tab" aria-selected="false">Profile</button></li>' +
|
||||||
'</ul>'
|
'</ul>'
|
||||||
var $tabs = $(tabsHTML).appendTo('#qunit-fixture')
|
var $tabs = $(tabsHTML).appendTo('#qunit-fixture')
|
||||||
|
|
||||||
$tabs.find('li:first-child a').bootstrapTab('show')
|
$tabs.find('li:first-child button').bootstrapTab('show')
|
||||||
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'shown tab has aria-selected = true')
|
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'shown tab has aria-selected = true')
|
||||||
assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'hidden tab has aria-selected = false')
|
assert.strictEqual($tabs.find('button:not(.active)').attr('aria-selected'), 'false', 'hidden tab has aria-selected = false')
|
||||||
|
|
||||||
$tabs.find('li:last-child a').trigger('click')
|
$tabs.find('li:last-child button').trigger('click')
|
||||||
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'after click, shown tab has aria-selected = true')
|
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'after click, shown tab has aria-selected = true')
|
||||||
assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'after click, hidden tab has aria-selected = false')
|
assert.strictEqual($tabs.find('button:not(.active)').attr('aria-selected'), 'false', 'after click, hidden tab has aria-selected = false')
|
||||||
|
|
||||||
$tabs.find('li:first-child a').bootstrapTab('show')
|
$tabs.find('li:first-child button').bootstrapTab('show')
|
||||||
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'shown tab has aria-selected = true')
|
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'shown tab has aria-selected = true')
|
||||||
assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'hidden tab has aria-selected = false')
|
assert.strictEqual($tabs.find('button:not(.active)').attr('aria-selected'), 'false', 'hidden tab has aria-selected = false')
|
||||||
|
|
||||||
$tabs.find('li:first-child a').trigger('click')
|
$tabs.find('li:first-child button').trigger('click')
|
||||||
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'after second show event, shown tab still has aria-selected = true')
|
assert.strictEqual($tabs.find('.active').attr('aria-selected'), 'true', 'after second show event, shown tab still has aria-selected = true')
|
||||||
assert.strictEqual($tabs.find('a:not(.active)').attr('aria-selected'), 'false', 'after second show event, hidden tab has aria-selected = false')
|
assert.strictEqual($tabs.find('button:not(.active)').attr('aria-selected'), 'false', 'after second show event, hidden tab has aria-selected = false')
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('selected tab should deactivate previous selected tab', function (assert) {
|
QUnit.test('selected tab should deactivate previous selected tab', function (assert) {
|
||||||
assert.expect(2)
|
assert.expect(2)
|
||||||
var tabsHTML = '<ul class="nav nav-tabs">' +
|
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
||||||
'<li class="nav-item"><a class="nav-link active" href="#home" data-toggle="tab">Home</a></li>' +
|
'<li class="nav-item"><button type="button" data-target="#home" role="tab" data-toggle="tab">Home</button></li>' +
|
||||||
'<li class="nav-item"><a class="nav-link" href="#profile" data-toggle="tab">Profile</a></li>' +
|
'<li class="nav-item"><button type="button" data-target="#profile" role="tab" data-toggle="tab">Profile</button></li>' +
|
||||||
'</ul>'
|
'</ul>'
|
||||||
var $tabs = $(tabsHTML).appendTo('#qunit-fixture')
|
var $tabs = $(tabsHTML).appendTo('#qunit-fixture')
|
||||||
|
|
||||||
$tabs.find('li:last-child a').trigger('click')
|
$tabs.find('li:last-child button').trigger('click')
|
||||||
assert.false($tabs.find('li:first-child a').hasClass('active'))
|
assert.false($tabs.find('li:first-child button').hasClass('active'))
|
||||||
assert.true($tabs.find('li:last-child a').hasClass('active'))
|
assert.true($tabs.find('li:last-child button').hasClass('active'))
|
||||||
})
|
|
||||||
|
|
||||||
QUnit.test('selected tab should deactivate previous selected link in dropdown', function (assert) {
|
|
||||||
assert.expect(3)
|
|
||||||
var tabsHTML = '<ul class="nav nav-tabs">' +
|
|
||||||
'<li class="nav-item"><a class="nav-link" href="#home" data-toggle="tab">Home</a></li>' +
|
|
||||||
'<li class="nav-item"><a class="nav-link" href="#profile" data-toggle="tab">Profile</a></li>' +
|
|
||||||
'<li class="nav-item dropdown"><a class="nav-link dropdown-toggle active" data-toggle="dropdown" href="#">Dropdown</a>' +
|
|
||||||
'<div class="dropdown-menu">' +
|
|
||||||
'<a class="dropdown-item active" href="#dropdown1" id="dropdown1-tab" data-toggle="tab">@fat</a>' +
|
|
||||||
'<a class="dropdown-item" href="#dropdown2" id="dropdown2-tab" data-toggle="tab">@mdo</a>' +
|
|
||||||
'</div>' +
|
|
||||||
'</li>' +
|
|
||||||
'</ul>'
|
|
||||||
var $tabs = $(tabsHTML).appendTo('#qunit-fixture')
|
|
||||||
|
|
||||||
$tabs.find('li:first-child a').trigger('click')
|
|
||||||
assert.true($tabs.find('li:first-child a').hasClass('active'))
|
|
||||||
assert.false($tabs.find('li:last-child a').hasClass('active'))
|
|
||||||
assert.false($tabs.find('li:last-child .dropdown-menu a:first-child').hasClass('active'))
|
|
||||||
})
|
})
|
||||||
|
|
||||||
QUnit.test('should support li > .dropdown-item', function (assert) {
|
QUnit.test('should support li > .dropdown-item', function (assert) {
|
||||||
@ -372,9 +365,9 @@ $(function () {
|
|||||||
var done = assert.async()
|
var done = assert.async()
|
||||||
var tabsHTML =
|
var tabsHTML =
|
||||||
'<nav class="nav nav-tabs" role="tablist">' +
|
'<nav class="nav nav-tabs" role="tablist">' +
|
||||||
' <a id="tab1" href="#x-tab1" class="nav-link" data-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</a>' +
|
' <button type="button" id="tab1" data-target="#x-tab1" class="nav-link" data-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</button>' +
|
||||||
' <a href="#x-tab2" class="nav-link active" data-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</a>' +
|
' <button type="button" data-target="#x-tab2" class="nav-link active" data-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</button>' +
|
||||||
' <a href="#x-tab3" class="nav-link" data-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</a>' +
|
' <button type="button" data-target="#x-tab3" class="nav-link" data-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</button>' +
|
||||||
'</nav>' +
|
'</nav>' +
|
||||||
'<div class="tab-content">' +
|
'<div class="tab-content">' +
|
||||||
' <div class="tab-pane" id="x-tab1" role="tabpanel">' +
|
' <div class="tab-pane" id="x-tab1" role="tabpanel">' +
|
||||||
@ -409,8 +402,8 @@ $(function () {
|
|||||||
assert.expect(6)
|
assert.expect(6)
|
||||||
var done = assert.async()
|
var done = assert.async()
|
||||||
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
var tabsHTML = '<ul class="nav nav-tabs" role="tablist">' +
|
||||||
'<li class="nav-item" role="presentation"><a id="tab-home" href="#home" class="nav-link" data-toggle="tab" role="tab">Home</a></li>' +
|
'<li class="nav-item" role="presentation"><button type="button" id="tab-home" data-target="#home" class="nav-link" data-toggle="tab" role="tab">Home</button></li>' +
|
||||||
'<li class="nav-item" role="presentation"><a id="tab-profile" href="#profile" class="nav-link" data-toggle="tab" role="tab">Profile</a></li>' +
|
'<li class="nav-item" role="presentation"><button type="button" id="tab-profile" data-target="#profile" class="nav-link" data-toggle="tab" role="tab">Profile</button></li>' +
|
||||||
'</ul>' +
|
'</ul>' +
|
||||||
'<div class="tab-content">' +
|
'<div class="tab-content">' +
|
||||||
'<div class="tab-pane fade" id="home" role="tabpanel"></div>' +
|
'<div class="tab-pane fade" id="home" role="tabpanel"></div>' +
|
||||||
@ -489,10 +482,10 @@ $(function () {
|
|||||||
var html = [
|
var html = [
|
||||||
'<ul class="nav nav-tabs" role="tablist">',
|
'<ul class="nav nav-tabs" role="tablist">',
|
||||||
' <li class="nav-item" role="presentation">',
|
' <li class="nav-item" role="presentation">',
|
||||||
' <a class="nav-link nav-tab" href="#home" role="tab" data-toggle="tab">Home</a>',
|
' <button type="button" class="nav-link nav-tab" data-target="#home" role="tab" data-toggle="tab">Home</button>',
|
||||||
' </li>',
|
' </li>',
|
||||||
' <li class="nav-item" role="presentation">',
|
' <li class="nav-item" role="presentation">',
|
||||||
' <a id="secondNav" class="nav-link nav-tab" href="#profile" role="tab" data-toggle="tab">Profile</a>',
|
' <button type="button" id="secondNav" class="nav-link nav-tab" data-target="#profile" role="tab" data-toggle="tab">Profile</button>',
|
||||||
' </li>',
|
' </li>',
|
||||||
'</ul>',
|
'</ul>',
|
||||||
'<div class="tab-content" role="presentation">',
|
'<div class="tab-content" role="presentation">',
|
||||||
@ -517,10 +510,10 @@ $(function () {
|
|||||||
var html = [
|
var html = [
|
||||||
'<ul class="nav nav-tabs" role="tablist">',
|
'<ul class="nav nav-tabs" role="tablist">',
|
||||||
' <li class="nav-item" role="presentation">',
|
' <li class="nav-item" role="presentation">',
|
||||||
' <a class="nav-link nav-tab" href="#home" role="tab" data-toggle="tab">Home</a>',
|
' <button type="button" class="nav-link nav-tab" data-target="#home" role="tab" data-toggle="tab">Home</button>',
|
||||||
' </li>',
|
' </li>',
|
||||||
' <li class="nav-item" role="presentation">',
|
' <li class="nav-item" role="presentation">',
|
||||||
' <a id="secondNav" class="nav-link nav-tab" href="#profile" role="tab" data-toggle="tab">Profile</a>',
|
' <button type="button" id="secondNav" class="nav-link nav-tab" data-target="#profile" role="tab" data-toggle="tab">Profile</button>',
|
||||||
' </li>',
|
' </li>',
|
||||||
'</ul>',
|
'</ul>',
|
||||||
'<div class="tab-content">',
|
'<div class="tab-content">',
|
||||||
|
@ -19,16 +19,16 @@
|
|||||||
|
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" data-toggle="tab" href="#home" role="tab">Home</a>
|
<button type="button" class="nav-link active" data-toggle="tab" data-target="#home" role="tab" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#profile" role="tab">Profile</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#profile" role="tab">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#fat" role="tab">@fat</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#fat" role="tab">@fat</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#mdo" role="tab">@mdo</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#mdo" role="tab">@mdo</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -55,16 +55,16 @@
|
|||||||
|
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" data-toggle="tab" href="#home2" role="tab">Home</a>
|
<button type="button" class="nav-link active" data-toggle="tab" data-target="#home2" role="tab" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#profile2" role="tab">Profile</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#profile2" role="tab">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#fat2" role="tab">@fat</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#fat2" role="tab">@fat</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#mdo2" role="tab">@mdo</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#mdo2" role="tab">@mdo</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -91,16 +91,16 @@
|
|||||||
|
|
||||||
<ul class="nav nav-tabs" role="tablist">
|
<ul class="nav nav-tabs" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#home3" role="tab">Home</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#home3" role="tab">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#profile3" role="tab">Profile</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#profile3" role="tab">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#fat3" role="tab">@fat</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#fat3" role="tab">@fat</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" data-toggle="tab" href="#mdo3" role="tab">@mdo</a>
|
<button type="button" class="nav-link" data-toggle="tab" data-target="#mdo3" role="tab">@mdo</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -159,26 +159,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h4>Tabs with nav (with fade)</h4>
|
<h4>Tabs with nav and using links (with fade)</h4>
|
||||||
<nav class="nav nav-pills">
|
<nav>
|
||||||
<a class="nav-link nav-item active" data-toggle="tab" href="#home5">Home</a>
|
<div class="nav nav-pills" id="nav-tab" role="tablist">
|
||||||
<a class="nav-link nav-item" data-toggle="tab" href="#profile5">Profile</a>
|
<a class="nav-link nav-item active" role="tab" data-toggle="tab" href="#home5">Home</a>
|
||||||
<div class="nav-item dropdown">
|
<a class="nav-link nav-item" role="tab" data-toggle="tab" href="#profile5">Profile</a>
|
||||||
<a class="nav-link dropdown-toggle" href="#" id="dropdown5" data-toggle="dropdown" aria-expanded="false">Dropdown</a>
|
<a class="nav-link nav-item" role="tab" data-toggle="tab" href="#fat5">@fat</a>
|
||||||
<div class="dropdown-menu" aria-labelledby="dropdown5">
|
<a class="nav-link nav-item" role="tab" data-toggle="tab" href="#mdo5">@mdo</a>
|
||||||
<a class="dropdown-item" data-toggle="tab" href="#fat5">@fat</a>
|
<a class="nav-link nav-item disabled" role="tab" href="#">Disabled</a>
|
||||||
<a class="dropdown-item" data-toggle="tab" href="#mdo5">@mdo</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<a class="nav-link nav-item disabled" href="#">Disabled</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="tab-content" role="tabpanel">
|
<div class="tab-content">
|
||||||
<div role="tabpanel" class="tab-pane fade show active" id="home5">
|
<div class="tab-pane fade show active" id="home5" role="tabpanel">
|
||||||
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
||||||
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane fade" id="profile5">
|
<div class="tab-pane fade" id="profile5" role="tabpanel">
|
||||||
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
||||||
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
<p>Raw denim you probably haven't heard of them jean shorts Austin. Nesciunt tofu stumptown aliqua, retro synth master cleanse. Mustache cliche tempor, williamsburg carles vegan helvetica. Reprehenderit butcher retro keffiyeh dreamcatcher synth. Cosby sweater eu banh mi, qui irure terry richardson ex squid. Aliquip placeat salvia cillum iphone. Seitan aliquip quis cardigan american apparel, butcher voluptate nisi qui.</p>
|
||||||
</div>
|
</div>
|
||||||
@ -196,10 +193,10 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-4">
|
<div class="col-4">
|
||||||
<div class="list-group" id="list-tab" role="tablist">
|
<div class="list-group" id="list-tab" role="tablist">
|
||||||
<a class="list-group-item list-group-item-action active" id="list-home-list" data-toggle="tab" href="#list-home" role="tab" aria-controls="list-home">Home</a>
|
<button type="button" class="list-group-item list-group-item-action active" id="list-home-list" data-toggle="tab" data-target="#list-home" role="tab" aria-controls="list-home" aria-selected="true">Home</button>
|
||||||
<a class="list-group-item list-group-item-action" id="list-profile-list" data-toggle="tab" href="#list-profile" role="tab" aria-controls="list-profile">Profile</a>
|
<button type="button" class="list-group-item list-group-item-action" id="list-profile-list" data-toggle="tab" data-target="#list-profile" role="tab" aria-controls="list-profile">Profile</button>
|
||||||
<a class="list-group-item list-group-item-action" id="list-messages-list" data-toggle="tab" href="#list-messages" role="tab" aria-controls="list-messages">Messages</a>
|
<button type="button" class="list-group-item list-group-item-action" id="list-messages-list" data-toggle="tab" data-target="#list-messages" role="tab" aria-controls="list-messages">Messages</button>
|
||||||
<a class="list-group-item list-group-item-action" id="list-settings-list" data-toggle="tab" href="#list-settings" role="tab" aria-controls="list-settings">Settings</a>
|
<button type="button" class="list-group-item list-group-item-action" id="list-settings-list" data-toggle="tab" data-target="#list-settings" role="tab" aria-controls="list-settings">Settings</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-8">
|
<div class="col-8">
|
||||||
|
@ -37,10 +37,13 @@
|
|||||||
|
|
||||||
.nav-link {
|
.nav-link {
|
||||||
margin-bottom: -$nav-tabs-border-width;
|
margin-bottom: -$nav-tabs-border-width;
|
||||||
|
background-color: transparent;
|
||||||
border: $nav-tabs-border-width solid transparent;
|
border: $nav-tabs-border-width solid transparent;
|
||||||
@include border-top-radius($nav-tabs-border-radius);
|
@include border-top-radius($nav-tabs-border-radius);
|
||||||
|
|
||||||
@include hover-focus() {
|
@include hover-focus() {
|
||||||
|
// Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link
|
||||||
|
isolation: isolate;
|
||||||
border-color: $nav-tabs-link-hover-border-color;
|
border-color: $nav-tabs-link-hover-border-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +76,8 @@
|
|||||||
|
|
||||||
.nav-pills {
|
.nav-pills {
|
||||||
.nav-link {
|
.nav-link {
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
@include border-radius($nav-pills-border-radius);
|
@include border-radius($nav-pills-border-radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +307,7 @@ Use the tab JavaScript plugin—include it individually or through the compiled
|
|||||||
|
|
||||||
If you're building our JavaScript from source, it [requires `util.js`]({{< docsref "/getting-started/javascript#util" >}}).
|
If you're building our JavaScript from source, it [requires `util.js`]({{< docsref "/getting-started/javascript#util" >}}).
|
||||||
|
|
||||||
Dynamic tabbed interfaces, as described in the [<abbr title="Web Accessibility Initiative">WAI</abbr> <abbr title="Accessible Rich Internet Applications">ARIA</abbr> Authoring Practices](https://www.w3.org/TR/wai-aria-practices/#tabpanel), require `role="tablist"`, `role="tab"`, `role="tabpanel"`, and additional `aria-` attributes in order to convey their structure, functionality and current state to users of assistive technologies (such as screen readers).
|
Dynamic tabbed interfaces, as described in the [<abbr title="Web Accessibility Initiative">WAI</abbr> <abbr title="Accessible Rich Internet Applications">ARIA</abbr> Authoring Practices](https://www.w3.org/TR/wai-aria-practices/#tabpanel), require `role="tablist"`, `role="tab"`, `role="tabpanel"`, and additional `aria-` attributes in order to convey their structure, functionality and current state to users of assistive technologies (such as screen readers). As a best practice, we recommend using `<button>` elements for the tabs, as these are controls that trigger a dynamic change, rather than links that navigate to a new page or location.
|
||||||
|
|
||||||
{{< callout danger >}}
|
{{< callout danger >}}
|
||||||
Note that the tab JavaScript plugin **does not** support tabbed interfaces that contain dropdown menus, as these cause both usability and accessibility issues. From a usability perspective, the fact that the currently displayed tab's trigger element is not immediately visible (as it's inside the closed dropdown menu) can cause confusion. From an accessibility point of view, there is currently no sensible way to map this sort of construct to a standard WAI ARIA pattern, meaning that it cannot be easily made understandable to users of assistive technologies.
|
Note that the tab JavaScript plugin **does not** support tabbed interfaces that contain dropdown menus, as these cause both usability and accessibility issues. From a usability perspective, the fact that the currently displayed tab's trigger element is not immediately visible (as it's inside the closed dropdown menu) can cause confusion. From an accessibility point of view, there is currently no sensible way to map this sort of construct to a standard WAI ARIA pattern, meaning that it cannot be easily made understandable to users of assistive technologies.
|
||||||
@ -316,13 +316,13 @@ Note that the tab JavaScript plugin **does not** support tabbed interfaces that
|
|||||||
<div class="bd-example bd-example-tabs">
|
<div class="bd-example bd-example-tabs">
|
||||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="home-tab" data-toggle="tab" data-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#profile" type="button" role="tab" aria-controls="profile" aria-selected="false">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="contact-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a>
|
<button class="nav-link" id="contact-tab" data-toggle="tab" data-target="#contact" type="button" role="tab" aria-controls="contact" aria-selected="false">Contact</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="myTabContent">
|
<div class="tab-content" id="myTabContent">
|
||||||
@ -341,13 +341,13 @@ Note that the tab JavaScript plugin **does not** support tabbed interfaces that
|
|||||||
```html
|
```html
|
||||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="home-tab" data-toggle="tab" data-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#profile" type="button" role="tab" aria-controls="profile" aria-selected="false">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="contact-tab" data-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a>
|
<button class="nav-link" id="contact-tab" data-toggle="tab" data-target="#contact" type="button" role="tab" aria-controls="contact" aria-selected="false">Contact</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="myTabContent">
|
<div class="tab-content" id="myTabContent">
|
||||||
@ -362,9 +362,9 @@ To help fit your needs, this works with `<ul>`-based markup, as shown above, or
|
|||||||
<div class="bd-example bd-example-tabs">
|
<div class="bd-example bd-example-tabs">
|
||||||
<nav>
|
<nav>
|
||||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||||
<a class="nav-link active" id="nav-home-tab" data-toggle="tab" href="#nav-home" role="tab" aria-controls="nav-home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="nav-home-tab" data-toggle="tab" data-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>
|
||||||
<a class="nav-link" id="nav-profile-tab" data-toggle="tab" href="#nav-profile" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="nav-profile-tab" data-toggle="tab" data-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>
|
||||||
<a class="nav-link" id="nav-contact-tab" data-toggle="tab" href="#nav-contact" role="tab" aria-controls="nav-contact" aria-selected="false">Contact</a>
|
<button class="nav-link" id="nav-contact-tab" data-toggle="tab" data-target="#nav-contact" type="button" role="tab" aria-controls="nav-contact" aria-selected="false">Contact</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="tab-content" id="nav-tabContent">
|
<div class="tab-content" id="nav-tabContent">
|
||||||
@ -383,9 +383,9 @@ To help fit your needs, this works with `<ul>`-based markup, as shown above, or
|
|||||||
```html
|
```html
|
||||||
<nav>
|
<nav>
|
||||||
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
<div class="nav nav-tabs" id="nav-tab" role="tablist">
|
||||||
<a class="nav-link active" id="nav-home-tab" data-toggle="tab" href="#nav-home" role="tab" aria-controls="nav-home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="nav-home-tab" data-toggle="tab" data-target="#nav-home" type="button" role="tab" aria-controls="nav-home" aria-selected="true">Home</button>
|
||||||
<a class="nav-link" id="nav-profile-tab" data-toggle="tab" href="#nav-profile" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="nav-profile-tab" data-toggle="tab" data-target="#nav-profile" type="button" role="tab" aria-controls="nav-profile" aria-selected="false">Profile</button>
|
||||||
<a class="nav-link" id="nav-contact-tab" data-toggle="tab" href="#nav-contact" role="tab" aria-controls="nav-contact" aria-selected="false">Contact</a>
|
<button class="nav-link" id="nav-contact-tab" data-toggle="tab" data-target="#nav-contact" type="button" role="tab" aria-controls="nav-contact" aria-selected="false">Contact</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="tab-content" id="nav-tabContent">
|
<div class="tab-content" id="nav-tabContent">
|
||||||
@ -400,13 +400,13 @@ The tabs plugin also works with pills.
|
|||||||
<div class="bd-example bd-example-tabs">
|
<div class="bd-example bd-example-tabs">
|
||||||
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" id="pills-home-tab" data-toggle="pill" href="#pills-home" role="tab" aria-controls="pills-home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="pills-home-tab" data-toggle="pill" data-target="#pills-home" type="button" role="tab" aria-controls="pills-home" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="pills-profile-tab" data-toggle="pill" href="#pills-profile" role="tab" aria-controls="pills-profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="pills-profile-tab" data-toggle="pill" data-target="#pills-profile" type="button" role="tab" aria-controls="pills-profile" aria-selected="false">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="pills-contact-tab" data-toggle="pill" href="#pills-contact" role="tab" aria-controls="pills-contact" aria-selected="false">Contact</a>
|
<button class="nav-link" id="pills-contact-tab" data-toggle="pill" data-target="#pills-contact" type="button" role="tab" aria-controls="pills-contact" aria-selected="false">Contact</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="pills-tabContent">
|
<div class="tab-content" id="pills-tabContent">
|
||||||
@ -425,13 +425,13 @@ The tabs plugin also works with pills.
|
|||||||
```html
|
```html
|
||||||
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" id="pills-home-tab" data-toggle="pill" href="#pills-home" role="tab" aria-controls="pills-home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="pills-home-tab" data-toggle="pill" data-target="#pills-home" type="button" role="tab" aria-controls="pills-home" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="pills-profile-tab" data-toggle="pill" href="#pills-profile" role="tab" aria-controls="pills-profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="pills-profile-tab" data-toggle="pill" data-target="#pills-profile" type="button" role="tab" aria-controls="pills-profile" aria-selected="false">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="pills-contact-tab" data-toggle="pill" href="#pills-contact" role="tab" aria-controls="pills-contact" aria-selected="false">Contact</a>
|
<button class="nav-link" id="pills-contact-tab" data-toggle="pill" data-target="#pills-contact" type="button" role="tab" aria-controls="pills-contact" aria-selected="false">Contact</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tab-content" id="pills-tabContent">
|
<div class="tab-content" id="pills-tabContent">
|
||||||
@ -447,10 +447,10 @@ And with vertical pills.
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||||
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="v-pills-home-tab" data-toggle="pill" data-target="#v-pills-home" type="button" role="tab" aria-controls="v-pills-home" aria-selected="true">Home</button>
|
||||||
<a class="nav-link" id="v-pills-profile-tab" data-toggle="pill" href="#v-pills-profile" role="tab" aria-controls="v-pills-profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="v-pills-profile-tab" data-toggle="pill" data-target="#v-pills-profile" type="button" role="tab" aria-controls="v-pills-profile" aria-selected="false">Profile</button>
|
||||||
<a class="nav-link" id="v-pills-messages-tab" data-toggle="pill" href="#v-pills-messages" role="tab" aria-controls="v-pills-messages" aria-selected="false">Messages</a>
|
<button class="nav-link" id="v-pills-messages-tab" data-toggle="pill" data-target="#v-pills-messages" type="button" role="tab" aria-controls="v-pills-messages" aria-selected="false">Messages</button>
|
||||||
<a class="nav-link" id="v-pills-settings-tab" data-toggle="pill" href="#v-pills-settings" role="tab" aria-controls="v-pills-settings" aria-selected="false">Settings</a>
|
<button class="nav-link" id="v-pills-settings-tab" data-toggle="pill" data-target="#v-pills-settings" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false">Settings</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
@ -476,10 +476,10 @@ And with vertical pills.
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-3">
|
<div class="col-3">
|
||||||
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
|
||||||
<a class="nav-link active" id="v-pills-home-tab" data-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="v-pills-home-tab" data-toggle="pill" data-target="#v-pills-home" type="button" role="tab" aria-controls="v-pills-home" aria-selected="true">Home</button>
|
||||||
<a class="nav-link" id="v-pills-profile-tab" data-toggle="pill" href="#v-pills-profile" role="tab" aria-controls="v-pills-profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="v-pills-profile-tab" data-toggle="pill" data-target="#v-pills-profile" type="button" role="tab" aria-controls="v-pills-profile" aria-selected="false">Profile</buttona>
|
||||||
<a class="nav-link" id="v-pills-messages-tab" data-toggle="pill" href="#v-pills-messages" role="tab" aria-controls="v-pills-messages" aria-selected="false">Messages</a>
|
<button class="nav-link" id="v-pills-messages-tab" data-toggle="pill" data-target="#v-pills-messages" type="button" role="tab" aria-controls="v-pills-messages" aria-selected="false">Messages</button>
|
||||||
<a class="nav-link" id="v-pills-settings-tab" data-toggle="pill" href="#v-pills-settings" role="tab" aria-controls="v-pills-settings" aria-selected="false">Settings</a>
|
<button class="nav-link" id="v-pills-settings-tab" data-toggle="pill" data-target="#v-pills-settings" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false">Settings</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
@ -501,16 +501,16 @@ You can activate a tab or pill navigation without writing any JavaScript by simp
|
|||||||
<!-- Nav tabs -->
|
<!-- Nav tabs -->
|
||||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="home-tab" data-toggle="tab" data-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#profile" type="button" role="tab" aria-controls="profile" aria-selected="false">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="messages-tab" data-toggle="tab" href="#messages" role="tab" aria-controls="messages" aria-selected="false">Messages</a>
|
<button class="nav-link" id="messages-tab" data-toggle="tab" data-target="#messages" type="button" role="tab" aria-controls="messages" aria-selected="false">Messages</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="settings-tab" data-toggle="tab" href="#settings" role="tab" aria-controls="settings" aria-selected="false">Settings</a>
|
<button class="nav-link" id="settings-tab" data-toggle="tab" data-target="#settings" type="button" role="tab" aria-controls="settings" aria-selected="false">Settings</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -528,7 +528,7 @@ You can activate a tab or pill navigation without writing any JavaScript by simp
|
|||||||
Enable tabbable tabs via JavaScript (each tab needs to be activated individually):
|
Enable tabbable tabs via JavaScript (each tab needs to be activated individually):
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$('#myTab a').on('click', function (event) {
|
$('#myTab button').on('click', function (event) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
$(this).tab('show')
|
$(this).tab('show')
|
||||||
})
|
})
|
||||||
@ -537,10 +537,10 @@ $('#myTab a').on('click', function (event) {
|
|||||||
You can activate individual tabs in several ways:
|
You can activate individual tabs in several ways:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$('#myTab a[href="#profile"]').tab('show') // Select tab by name
|
$('#myTab button[data-target="#profile"]').tab('show') // Select tab by name
|
||||||
$('#myTab li:first-child a').tab('show') // Select first tab
|
$('#myTab li:first-child button').tab('show') // Select first tab
|
||||||
$('#myTab li:last-child a').tab('show') // Select last tab
|
$('#myTab li:last-child button').tab('show') // Select last tab
|
||||||
$('#myTab li:nth-child(3) a').tab('show') // Select third tab
|
$('#myTab li:nth-child(3) button').tab('show') // Select third tab
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fade effect
|
### Fade effect
|
||||||
@ -564,21 +564,21 @@ To make tabs fade in, add `.fade` to each `.tab-pane`. The first tab pane must a
|
|||||||
|
|
||||||
#### $().tab
|
#### $().tab
|
||||||
|
|
||||||
Activates a tab element and content container. Tab should have either a `data-target` or an `href` targeting a container node in the DOM.
|
Activates a tab element and content container. Tab should have either a `data-target` or, if using a link, an `href` attribute targeting a container node in the DOM.
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
<ul class="nav nav-tabs" id="myTab" role="tablist">
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a>
|
<button class="nav-link active" id="home-tab" data-toggle="tab" data-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">Home</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a>
|
<button class="nav-link" id="profile-tab" data-toggle="tab" data-target="#profile" type="button" role="tab" aria-controls="profile" aria-selected="false">Profile</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="messages-tab" data-toggle="tab" href="#messages" role="tab" aria-controls="messages" aria-selected="false">Messages</a>
|
<button class="nav-link" id="messages-tab" data-toggle="tab" data-target="#messages" type="button" role="tab" aria-controls="messages" aria-selected="false">Messages</button>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item" role="presentation">
|
<li class="nav-item" role="presentation">
|
||||||
<a class="nav-link" id="settings-tab" data-toggle="tab" href="#settings" role="tab" aria-controls="settings" aria-selected="false">Settings</a>
|
<button class="nav-link" id="settings-tab" data-toggle="tab" data-target="#settings" type="button" role="tab" aria-controls="settings" aria-selected="false">Settings</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -591,7 +591,7 @@ Activates a tab element and content container. Tab should have either a `data-ta
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(function () {
|
$(function () {
|
||||||
$('#myTab li:last-child a').tab('show')
|
$('#myTab li:last-child button').tab('show')
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
@ -647,7 +647,7 @@ If no tab was already active, then the `hide.bs.tab` and `hidden.bs.tab` events
|
|||||||
</table>
|
</table>
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (event) {
|
$('button[data-toggle="tab"]').on('shown.bs.tab', function (event) {
|
||||||
event.target // newly activated tab
|
event.target // newly activated tab
|
||||||
event.relatedTarget // previous active tab
|
event.relatedTarget // previous active tab
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user