Dynamic tabs: use buttons rather than links (#32630)

* Dynamic tabs: use buttons rather than links

- change docs
- add mention that tabs should be <button> elements
- tweak styles to neutralise border and background

* Update js unit and visual test accordingly

- replace links with buttons
- make one specific test that uses links instead of buttons, as we still want to support it despite it being non-semantically appropriate
- Leaving a couple of tests for now. The test for removed tabs should be redone so that tabs are removed programmatically (as the approach of having that close button inside the link is invalid and broken markup). The test for dropdowns should be removed together we actually ripping out the handling for dropdowns in the tab.js code (arguably a breaking change, though we discouraged this for a few versions and effectively "deprecated" it)

* Add isolation:isolate to prevent focus being overlapped

https://github.com/twbs/bootstrap/pull/32630#issuecomment-756015766
This commit is contained in:
Patrick H. Lauke 2021-02-09 05:23:45 +00:00 committed by GitHub
parent c93d754d35
commit 96be06e32b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 122 deletions

View File

@ -21,15 +21,39 @@ describe('Tab', () => {
}) })
describe('show', () => { describe('show', () => {
it('should activate element by tab id', done => { it('should activate element by tab id (using buttons, the preferred semantic way)', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav">', '<ul class="nav" role="tablist">',
' <li><a href="#home" role="tab">Home</a></li>', ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
' <li><a id="triggerProfile" role="tab" href="#profile">Profile</a></li>', ' <li><button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button></li>',
'</ul>', '</ul>',
'<ul>', '<ul>',
' <li id="home"></li>', ' <li id="home" role="tabpanel"></li>',
' <li id="profile"></li>', ' <li id="profile" role="tabpanel"></li>',
'</ul>'
].join('')
const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
const tab = new Tab(profileTriggerEl)
profileTriggerEl.addEventListener('shown.bs.tab', () => {
expect(fixtureEl.querySelector('#profile').classList.contains('active')).toEqual(true)
expect(profileTriggerEl.getAttribute('aria-selected')).toEqual('true')
done()
})
tab.show()
})
it('should activate element by tab id (using links for tabs - not ideal, but still supported)', done => {
fixtureEl.innerHTML = [
'<ul class="nav" role="tablist">',
' <li><a href="#home" role="tab">Home</a></li>',
' <li><a id="triggerProfile" href="#profile" role="tab">Profile</a></li>',
'</ul>',
'<ul>',
' <li id="home" role="tabpanel"></li>',
' <li id="profile" role="tabpanel"></li>',
'</ul>' '</ul>'
].join('') ].join('')
@ -48,12 +72,12 @@ describe('Tab', () => {
it('should activate element by tab id in ordered list', done => { it('should activate element by tab id in ordered list', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ol class="nav nav-pills">', '<ol class="nav nav-pills">',
' <li><a href="#home">Home</a></li>', ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
' <li><a id="triggerProfile" href="#profile">Profile</a></li>', ' <li><button type="button" id="triggerProfile" href="#profile" role="tab">Profile</button></li>',
'</ol>', '</ol>',
'<ol>', '<ol>',
' <li id="home"></li>', ' <li id="home" role="tabpanel"></li>',
' <li id="profile"></li>', ' <li id="profile" role="tabpanel"></li>',
'</ol>' '</ol>'
].join('') ].join('')
@ -71,10 +95,10 @@ describe('Tab', () => {
it('should activate element by tab id in nav list', done => { it('should activate element by tab id in nav list', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<nav class="nav">', '<nav class="nav">',
' <a href="#home">Home</a>', ' <button type="button" data-bs-target="#home" role="tab">Home</button>',
' <a id="triggerProfile" href="#profile">Profile</a>', ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</a>',
'</nav>', '</nav>',
'<nav><div id="home"></div><div id="profile"></div></nav>' '<div><div id="home" role="tabpanel"></div><div id="profile" role="tabpanel"></div></div>'
].join('') ].join('')
const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
@ -90,11 +114,11 @@ describe('Tab', () => {
it('should activate element by tab id in list group', done => { it('should activate element by tab id in list group', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<div class="list-group">', '<div class="list-group" role="tablist">',
' <a href="#home">Home</a>', ' <button type="button" data-bs-target="#home" role="tab">Home</button>',
' <a id="triggerProfile" href="#profile">Profile</a>', ' <button type="button" id="triggerProfile" data-bs-target="#profile" role="tab">Profile</button>',
'</div>', '</div>',
'<nav><div id="home"></div><div id="profile"></div></nav>' '<div><div id="home" role="tabpanel"></div><div id="profile" role="tabpanel"></div></div>'
].join('') ].join('')
const profileTriggerEl = fixtureEl.querySelector('#triggerProfile') const profileTriggerEl = fixtureEl.querySelector('#triggerProfile')
@ -135,8 +159,8 @@ describe('Tab', () => {
it('should not fire shown when tab is already active', done => { it('should not fire shown when tab is already active', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav nav-tabs" role="tablist">', '<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-bs-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" href="#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>',
@ -144,7 +168,7 @@ describe('Tab', () => {
'</div>' '</div>'
].join('') ].join('')
const triggerActive = fixtureEl.querySelector('a.active') const triggerActive = fixtureEl.querySelector('button.active')
const tab = new Tab(triggerActive) const tab = new Tab(triggerActive)
triggerActive.addEventListener('shown.bs.tab', () => { triggerActive.addEventListener('shown.bs.tab', () => {
@ -161,8 +185,8 @@ describe('Tab', () => {
it('should not fire shown when tab is disabled', done => { it('should not fire shown when tab is disabled', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav nav-tabs" role="tablist">', '<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-bs-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 disabled" role="tab">Profile</a></li>', ' <li class="nav-item" role="presentation"><button type="button" data-bs-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>',
@ -170,7 +194,7 @@ describe('Tab', () => {
'</div>' '</div>'
].join('') ].join('')
const triggerDisabled = fixtureEl.querySelector('a.disabled') const triggerDisabled = fixtureEl.querySelector('button.disabled')
const tab = new Tab(triggerDisabled) const tab = new Tab(triggerDisabled)
triggerDisabled.addEventListener('shown.bs.tab', () => { triggerDisabled.addEventListener('shown.bs.tab', () => {
@ -187,8 +211,8 @@ describe('Tab', () => {
it('show and shown events should reference correct relatedTarget', done => { it('show and shown events should reference correct relatedTarget', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav nav-tabs" role="tablist">', '<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-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
' <li class="nav-item" role="presentation"><a id="triggerProfile" href="#profile" class="nav-link" role="tab">Profile</a></li>', ' <li class="nav-item" role="presentation"><button type="button" id="triggerProfile" data-bs-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>',
@ -200,13 +224,13 @@ describe('Tab', () => {
const secondTab = new Tab(secondTabTrigger) const secondTab = new Tab(secondTabTrigger)
secondTabTrigger.addEventListener('show.bs.tab', ev => { secondTabTrigger.addEventListener('show.bs.tab', ev => {
expect(ev.relatedTarget.hash).toEqual('#home') expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home')
}) })
secondTabTrigger.addEventListener('shown.bs.tab', ev => { secondTabTrigger.addEventListener('shown.bs.tab', ev => {
expect(ev.relatedTarget.hash).toEqual('#home') expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#home')
expect(secondTabTrigger.getAttribute('aria-selected')).toEqual('true') expect(secondTabTrigger.getAttribute('aria-selected')).toEqual('true')
expect(fixtureEl.querySelector('a:not(.active)').getAttribute('aria-selected')).toEqual('false') expect(fixtureEl.querySelector('button:not(.active)').getAttribute('aria-selected')).toEqual('false')
done() done()
}) })
@ -215,13 +239,13 @@ describe('Tab', () => {
it('should fire hide and hidden events', done => { it('should fire hide and hidden events', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav">', '<ul class="nav" role="tablist">',
' <li><a href="#home">Home</a></li>', ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
' <li><a href="#profile">Profile</a></li>', ' <li><button type="button" data-bs-target="#profile">Profile</button></li>',
'</ul>' '</ul>'
].join('') ].join('')
const triggerList = fixtureEl.querySelectorAll('a') const triggerList = fixtureEl.querySelectorAll('button')
const firstTab = new Tab(triggerList[0]) const firstTab = new Tab(triggerList[0])
const secondTab = new Tab(triggerList[1]) const secondTab = new Tab(triggerList[1])
@ -232,12 +256,12 @@ describe('Tab', () => {
triggerList[0].addEventListener('hide.bs.tab', ev => { triggerList[0].addEventListener('hide.bs.tab', ev => {
hideCalled = true hideCalled = true
expect(ev.relatedTarget.hash).toEqual('#profile') expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile')
}) })
triggerList[0].addEventListener('hidden.bs.tab', ev => { triggerList[0].addEventListener('hidden.bs.tab', ev => {
expect(hideCalled).toEqual(true) expect(hideCalled).toEqual(true)
expect(ev.relatedTarget.hash).toEqual('#profile') expect(ev.relatedTarget.getAttribute('data-bs-target')).toEqual('#profile')
done() done()
}) })
@ -246,13 +270,13 @@ describe('Tab', () => {
it('should not fire hidden when hide is prevented', done => { it('should not fire hidden when hide is prevented', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav">', '<ul class="nav" role="tablist">',
' <li><a href="#home">Home</a></li>', ' <li><button type="button" data-bs-target="#home" role="tab">Home</button></li>',
' <li><a href="#profile">Profile</a></li>', ' <li><button type="button" data-bs-target="#profile" role="tab">Profile</button></li>',
'</ul>' '</ul>'
].join('') ].join('')
const triggerList = fixtureEl.querySelectorAll('a') const triggerList = fixtureEl.querySelectorAll('button')
const firstTab = new Tab(triggerList[0]) const firstTab = new Tab(triggerList[0])
const secondTab = new Tab(triggerList[1]) const secondTab = new Tab(triggerList[1])
const expectDone = () => { const expectDone = () => {
@ -423,8 +447,8 @@ describe('Tab', () => {
it('should create dynamically a tab', done => { it('should create dynamically a tab', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav nav-tabs" role="tablist">', '<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-bs-target="#home" class="nav-link active" role="tab" aria-selected="true">Home</button></li>',
' <li class="nav-item" role="presentation"><a id="triggerProfile" data-bs-toggle="tab" href="#profile" class="nav-link" role="tab">Profile</a></li>', ' <li class="nav-item" role="presentation"><button type="button" id="triggerProfile" data-bs-toggle="tab" data-bs-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>',
@ -469,15 +493,15 @@ describe('Tab', () => {
it('should handle nested tabs', done => { it('should handle nested tabs', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<nav class="nav nav-tabs" role="tablist">', '<nav class="nav nav-tabs" role="tablist">',
' <a id="tab1" href="#x-tab1" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</a>', ' <button type="button" id="tab1" data-bs-target="#x-tab1" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab1">Tab 1</button>',
' <a href="#x-tab2" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</a>', ' <button type="button" data-bs-target="#x-tab2" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab2" aria-selected="true">Tab 2</button>',
' <a href="#x-tab3" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-tab3">Tab 3</a>', ' <button type="button" data-bs-target="#x-tab3" class="nav-link" data-bs-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">',
' <nav class="nav nav-tabs" role="tablist">', ' <nav class="nav nav-tabs" role="tablist">',
' <a href="#nested-tab1" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab1" aria-selected="true">Nested Tab 1</a>', ' <button type="button" data-bs-target="#nested-tab1" class="nav-link active" data-bs-toggle="tab" role="tab" aria-controls="x-tab1" aria-selected="true">Nested Tab 1</button>',
' <a id="tabNested2" href="#nested-tab2" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-profile">Nested Tab2</a>', ' <button type="button" id="tabNested2" data-bs-target="#nested-tab2" class="nav-link" data-bs-toggle="tab" role="tab" aria-controls="x-profile">Nested Tab2</button>',
' </nav>', ' </nav>',
' <div class="tab-content">', ' <div class="tab-content">',
' <div class="tab-pane active" id="nested-tab1" role="tabpanel">Nested Tab1 Content</div>', ' <div class="tab-pane active" id="nested-tab1" role="tabpanel">Nested Tab1 Content</div>',
@ -509,8 +533,8 @@ describe('Tab', () => {
it('should not remove fade class if no active pane is present', done => { it('should not remove fade class if no active pane is present', done => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<ul class="nav nav-tabs" role="tablist">', '<ul class="nav nav-tabs" role="tablist">',
' <li class="nav-item" role="presentation"><a id="tab-home" href="#home" class="nav-link" data-bs-toggle="tab" role="tab">Home</a></li>', ' <li class="nav-item" role="presentation"><button type="button" id="tab-home" data-bs-target="#home" class="nav-link" data-bs-toggle="tab" role="tab">Home</button></li>',
' <li class="nav-item" role="presentation"><a id="tab-profile" href="#profile" class="nav-link" data-bs-toggle="tab" role="tab">Profile</a></li>', ' <li class="nav-item" role="presentation"><button type="button" id="tab-profile" data-bs-target="#profile" class="nav-link" data-bs-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>',
@ -547,10 +571,10 @@ describe('Tab', () => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<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-bs-toggle="tab">Home</a>', ' <button type="button" class="nav-link nav-tab" data-bs-target="#home" role="tab" data-bs-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-bs-toggle="tab">Profile</a>', ' <button type="button" id="secondNav" class="nav-link nav-tab" data-bs-target="#profile" role="tab" data-bs-toggle="tab">Profile</button>',
' </li>', ' </li>',
'</ul>', '</ul>',
'<div class="tab-content">', '<div class="tab-content">',
@ -573,10 +597,10 @@ describe('Tab', () => {
fixtureEl.innerHTML = [ fixtureEl.innerHTML = [
'<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-bs-toggle="tab">Home</a>', ' <button type="button" class="nav-link nav-tab" data-bs-target="#home" role="tab" data-bs-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-bs-toggle="tab">Profile</a>', ' <button type="button" id="secondNav" class="nav-link nav-tab" data-bs-target="#profile" role="tab" data-bs-toggle="tab">Profile</button>',
' </li>', ' </li>',
'</ul>', '</ul>',
'<div class="tab-content">', '<div class="tab-content">',

View File

@ -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-bs-toggle="tab" href="#home" role="tab">Home</a> <button type="button" class="nav-link active" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile" role="tab">Profile</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#fat" role="tab">@fat</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#mdo" role="tab">@mdo</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#home2" role="tab">Home</a> <button type="button" class="nav-link active" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile2" role="tab">Profile</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#fat2" role="tab">@fat</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#mdo2" role="tab">@mdo</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#home3" role="tab">Home</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile3" role="tab">Profile</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#fat3" role="tab">@fat</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#mdo3" role="tab">@mdo</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-target="#mdo3" role="tab">@mdo</button>
</li> </li>
</ul> </ul>
@ -127,16 +127,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-bs-toggle="tab" href="#home4" role="tab">Home</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-target="#home4" role="tab">Home</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<a class="nav-link" data-bs-toggle="tab" href="#profile4" role="tab">Profile</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-target="#profile4" role="tab">Profile</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<a class="nav-link" data-bs-toggle="tab" href="#fat4" role="tab">@fat</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-target="#fat4" role="tab">@fat</button>
</li> </li>
<li class="nav-item" role="presentation"> <li class="nav-item" role="presentation">
<a class="nav-link" data-bs-toggle="tab" href="#mdo4" role="tab">@mdo</a> <button type="button" class="nav-link" data-bs-toggle="tab" data-bs-target="#mdo4" 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-bs-toggle="tab" href="#home5">Home</a> <div class="nav nav-pills" id="nav-tab" role="tablist">
<a class="nav-link nav-item" data-bs-toggle="tab" href="#profile5">Profile</a> <a class="nav-link nav-item active" role="tab" data-bs-toggle="tab" href="#home5">Home</a>
<div class="nav-item dropdown"> <a class="nav-link nav-item" role="tab" data-bs-toggle="tab" href="#profile5">Profile</a>
<a class="nav-link dropdown-toggle" href="#" id="dropdown5" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a> <a class="nav-link nav-item" role="tab" data-bs-toggle="tab" href="#fat5">@fat</a>
<ul class="dropdown-menu" aria-labelledby="dropdown5"> <a class="nav-link nav-item" role="tab" data-bs-toggle="tab" href="#mdo5">@mdo</a>
<li><a class="dropdown-item" data-bs-toggle="tab" href="#fat5">@fat</a></li> <a class="nav-link nav-item disabled" role="tab" href="#">Disabled</a>
<li><a class="dropdown-item" data-bs-toggle="tab" href="#mdo5">@mdo</a></li>
</ul>
</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-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-target="#list-settings" role="tab" aria-controls="list-settings">Settings</button>
</div> </div>
</div> </div>
<div class="col-8"> <div class="col-8">

View File

@ -43,12 +43,15 @@
.nav-link { .nav-link {
margin-bottom: -$nav-tabs-border-width; margin-bottom: -$nav-tabs-border-width;
background: none;
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);
&:hover, &:hover,
&:focus { &:focus {
border-color: $nav-tabs-link-hover-border-color; border-color: $nav-tabs-link-hover-border-color;
// Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link
isolation: isolate;
} }
&.disabled { &.disabled {
@ -80,6 +83,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);
} }

View File

@ -308,20 +308,20 @@ Add dropdown menus with a little extra HTML and the [dropdowns JavaScript plugin
Use the tab JavaScript plugin—include it individually or through the compiled `bootstrap.js` file—to extend our navigational tabs and pills to create tabbable panes of local content. Use the tab JavaScript plugin—include it individually or through the compiled `bootstrap.js` file—to extend our navigational tabs and pills to create tabbable panes of local content.
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.
Note that dynamic tabbed interfaces should <em>not</em> contain dropdown menus, as this causes 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 dynamic tabbed interfaces should <em>not</em> contain dropdown menus, as this causes 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.
<div class="bd-example"> <div class="bd-example">
<ul class="nav nav-tabs mb-3" id="myTab" role="tablist"> <ul class="nav nav-tabs mb-3" 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-bs-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a> <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a> <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a> <button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-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">
@ -340,13 +340,13 @@ Note that dynamic tabbed interfaces should <em>not</em> contain dropdown menus,
```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-bs-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a> <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a> <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#contact" role="tab" aria-controls="contact" aria-selected="false">Contact</a> <button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-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">
@ -361,9 +361,9 @@ To help fit your needs, this works with `<ul>`-based markup, as shown above, or
<div class="bd-example"> <div class="bd-example">
<nav> <nav>
<div class="nav nav-tabs mb-3" id="nav-tab" role="tablist"> <div class="nav nav-tabs mb-3" id="nav-tab" role="tablist">
<a class="nav-link active" id="nav-home-tab" data-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-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">
@ -382,9 +382,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-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-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-bs-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-bs-toggle="tab" data-bs-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">
@ -399,13 +399,13 @@ The tabs plugin also works with pills.
<div class="bd-example"> <div class="bd-example">
<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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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">
@ -424,13 +424,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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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">
@ -445,10 +445,10 @@ And with vertical pills.
<div class="bd-example"> <div class="bd-example">
<div class="d-flex align-items-start"> <div class="d-flex align-items-start">
<div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical"> <div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link active" id="v-pills-home-tab" data-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-target="#v-pills-settings" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false">Settings</button>
</div> </div>
<div class="tab-content" id="v-pills-tabContent"> <div class="tab-content" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab"> <div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
@ -470,10 +470,10 @@ And with vertical pills.
```html ```html
<div class="d-flex align-items-start"> <div class="d-flex align-items-start">
<div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical"> <div class="nav flex-column nav-pills me-3" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link active" id="v-pills-home-tab" data-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-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-bs-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-bs-toggle="pill" data-bs-target="#v-pills-settings" type="button" role="tab" aria-controls="v-pills-settings" aria-selected="false">Settings</button>
</div> </div>
<div class="tab-content" id="v-pills-tabContent"> <div class="tab-content" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">...</div> <div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">...</div>
@ -492,16 +492,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-bs-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a> <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a> <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#messages" role="tab" aria-controls="messages" aria-selected="false">Messages</a> <button class="nav-link" id="messages-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#settings" role="tab" aria-controls="settings" aria-selected="false">Settings</a> <button class="nav-link" id="settings-tab" data-bs-toggle="tab" hdata-bs-targetref="#settings" type="button" role="tab" aria-controls="settings" aria-selected="false">Settings</button>
</li> </li>
</ul> </ul>
@ -561,21 +561,21 @@ To make tabs fade in, add `.fade` to each `.tab-pane`. The first tab pane must a
#### constructor #### constructor
Activates a tab element and content container. Tab should have either a `data-bs-target` or an `href` targeting a container node in the DOM. Activates a tab element and content container. Tab should have either a `data-bs-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-bs-toggle="tab" href="#home" role="tab" aria-controls="home" aria-selected="true">Home</a> <button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#profile" role="tab" aria-controls="profile" aria-selected="false">Profile</a> <button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#messages" role="tab" aria-controls="messages" aria-selected="false">Messages</a> <button class="nav-link" id="messages-tab" data-bs-toggle="tab" data-bs-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-bs-toggle="tab" href="#settings" role="tab" aria-controls="settings" aria-selected="false">Settings</a> <button class="nav-link" id="settings-tab" data-bs-toggle="tab" data-bs-target="#settings" type="button" role="tab" aria-controls="settings" aria-selected="false">Settings</button>
</li> </li>
</ul> </ul>
@ -657,7 +657,7 @@ If no tab was already active, then the `hide.bs.tab` and `hidden.bs.tab` events
</table> </table>
```js ```js
var tabEl = document.querySelector('a[data-bs-toggle="tab"]') var tabEl = document.querySelector('button[data-bs-toggle="tab"]')
tabEl.addEventListener('shown.bs.tab', function (event) { tabEl.addEventListener('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