The Navs & Tabs component provides flexible, customizable navigation with horizontal or vertical layouts, color variants, and tabbable regions.
| Class Name | Type | Description |
|---|---|---|
| nav | Component | Nav container |
| nav-item | Inner | Nav item |
| nav-link | Inner | Nav link |
| tab-content | Inner | Tab content |
| tab-pane | Inner | Tab panel |
| nav-primary | Color | Primary color |
| nav-secondary | Color | Secondary color |
| nav-info | Color | Info color |
| nav-warning | Color | Warning color |
| nav-success | Color | Success color |
| nav-danger | Color | Danger color |
| nav-neutral | Color | Neutral color |
| nav-underline | Modifier | Underlined style |
| nav-tabs | Modifier | Tab style |
Hummingbird’s navigation provides general markup and styles via the base .nav class, including active and disabled states. Built with flexbox, it offers a solid foundation, link padding for larger hit areas, and basic disabled styling.
HTML
<ul class="nav nav-underline">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>Add the .nav-tabs class to the basic .nav to create a tabbed interface. Use these tabs with JavaScript plugin to build tabbable regions.
HTML
<ul class="nav nav-tabs">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>Tabs support multiple color variants. Apply a variant class such as .nav-primary, .nav-secondary, etc., to change the style.
HTML
<ul class="nav nav-primary">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>
<ul class="nav nav-secondary">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" aria-disabled="true">Disabled</a>
</li>
</ul>The nav component is built using a set of CSS variables. These variables provide flexibility for customizing styles.
.nav {
--nav-bg: transparent;
--nav-link-padding-x: --spacing(4);
--nav-link-padding-y: --spacing(2);
--nav-link-font-weight: var(--font-weight-medium);
--nav-link-color: var(--text-color-muted);
--nav-link-font-size: var(--text-base);
--nav-link-line-height: 1.5;
--nav-link-disabled-color: var(--color-disabled-color);
--nav-link-active-color: unset;
--nav-link-focus-ring-color: --alpha(var(--nav-link-active-color) / 30%);
}Use JavaScript in the familiar pattern of Bootstrap’s plugins with full additional TypeScript Support. Include the Tabs JavaScript plugin to enable navigation between tabs.
HTML
<ul class="nav nav-underline mb-4" id="myTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home-tab-pane" type="button" role="tab" aria-controls="home-tab-pane" aria-selected="true">Home</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-tab" data-bs-toggle="tab" data-bs-target="#profile-tab-pane" type="button" role="tab" aria-controls="profile-tab-pane" aria-selected="false">Profile</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact-tab-pane" type="button" role="tab" aria-controls="contact-tab-pane" aria-selected="false">Contact</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="disabled-tab" data-bs-toggle="tab" data-bs-target="#disabled-tab-pane" type="button" role="tab" aria-controls="disabled-tab-pane" aria-selected="false" disabled>Disabled</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="home-tab-pane" role="tabpanel" aria-labelledby="home-tab" tabindex="0">This is some placeholder content the <b>Home tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="profile-tab-pane" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">This is some placeholder content the <b>Profile tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="contact-tab-pane" role="tabpanel" aria-labelledby="contact-tab" tabindex="0">This is some placeholder content the <b>Contact tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="disabled-tab-pane" role="tabpanel" aria-labelledby="disabled-tab" tabindex="0">Disabled</div>
</div>Tabs work with <ul> based markup, as shown above, or with any custom markup. When using <nav>, avoid adding role=“tablist” directly, since it overrides the element’s native role as a navigation landmark. Instead, wrap the <nav> around another element (for example, a <div>) and apply role="tablist" there.
HTML
<nav>
<div class="nav nav-underline mb-4" id="nav-tab" role="tablist">
<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>
<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>
<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>
<button class="nav-link" id="nav-disabled-tab" data-bs-toggle="tab" data-bs-target="#nav-disabled" type="button" role="tab" aria-controls="nav-disabled" aria-selected="false" disabled>Disabled</button>
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
<div class="tab-pane fade show active" id="nav-home" role="tabpanel" aria-labelledby="nav-home-tab" tabindex="0">This is some placeholder content the <b>Home tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="nav-profile" role="tabpanel" aria-labelledby="nav-profile-tab" tabindex="0">This is some placeholder content the <b>Profile tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="nav-contact" role="tabpanel" aria-labelledby="nav-contact-tab" tabindex="0">This is some placeholder content the <b>Contact tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="nav-disabled" role="tabpanel" aria-labelledby="nav-disabled-tab" tabindex="0">Disabled</div>
</div>The tabs plugin also works with nav tabs & color variants.
HTML
<ul class="nav nav-tabs mb-4" id="nav-tab-lift" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="home-lift-tab" data-bs-toggle="tab" data-bs-target="#home-lift-tab-pane" type="button" role="tab" aria-controls="home-lift-tab-pane" aria-selected="true">Home</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-lift-tab" data-bs-toggle="tab" data-bs-target="#profile-lift-tab-pane" type="button" role="tab" aria-controls="profile-lift-tab-pane" aria-selected="false">Profile</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="contact-lift-tab" data-bs-toggle="tab" data-bs-target="#contact-lift-tab-pane" type="button" role="tab" aria-controls="contact-lift-tab-pane" aria-selected="false">Contact</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="disabled-lift-tab" data-bs-toggle="tab" data-bs-target="#disabled-lift-tab-pane" type="button" role="tab" aria-controls="disabled-lift-tab-pane" aria-selected="false" disabled>Disabled</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="home-lift-tab-pane" role="tabpanel" aria-labelledby="home-lift-tab" tabindex="0">This is some placeholder content the <b>Home tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="profile-lift-tab-pane" role="tabpanel" aria-labelledby="profile-lift-tab" tabindex="0">This is some placeholder content the <b>Profile tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="contact-lift-tab-pane" role="tabpanel" aria-labelledby="contact-lift-tab" tabindex="0">This is some placeholder content the <b>Contact tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="disabled-lift-tab-pane" role="tabpanel" aria-labelledby="disabled-lift-tab" tabindex="0">Disabled</div>
</div>HTML
<ul class="nav nav-primary mb-4" id="myColorTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="home-primary-tab" data-bs-toggle="tab" data-bs-target="#home-primary-tab-pane" type="button" role="tab" aria-controls="home-primary-tab-pane" aria-selected="true">Home</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="profile-primary-tab" data-bs-toggle="tab" data-bs-target="#profile-primary-tab-pane" type="button" role="tab" aria-controls="profile-primary-tab-pane" aria-selected="false">Profile</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="contact-primary-tab" data-bs-toggle="tab" data-bs-target="#contact-primary-tab-pane" type="button" role="tab" aria-controls="contact-primary-tab-pane" aria-selected="false">Contact</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="disabled-primary-tab" data-bs-toggle="tab" data-bs-target="#disabled-primary-tab-pane" type="button" role="tab" aria-controls="disabled-primary-tab-pane" aria-selected="false" disabled>Disabled</button>
</li>
</ul>
<div class="tab-content" id="myTabContent">
<div class="tab-pane fade show active" id="home-primary-tab-pane" role="tabpanel" aria-labelledby="home-primary-tab" tabindex="0">This is some placeholder content the <b>Home tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="profile-primary-tab-pane" role="tabpanel" aria-labelledby="profile-primary-tab" tabindex="0">This is some placeholder content the <b>Profile tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="contact-primary-tab-pane" role="tabpanel" aria-labelledby="contact-primary-tab" tabindex="0">This is some placeholder content the <b>Contact tab’s</b> associated content. Clicking another tab will toggle the visibility of this one for the next.</div>
<div class="tab-pane fade" id="disabled-primary-tab-pane" role="tabpanel" aria-labelledby="disabled-primary-tab" tabindex="0">Disabled</div>
</div>Dynamic tabbed interfaces, as outlined in the ARIA Authoring Practices Guide tabs pattern, require role="tablist", role="tab", role="tabpanel", and additional aria- attributes. These are essential for conveying their structure, functionality, and current state to users of assistive technologies, such as screen readers. As a recommended practice, using <button> elements for tabs is advisable, as these function as controls that trigger a dynamic change, rather than links that navigate to new pages or locations.
In adherence to the ARIA Authoring Practices pattern, only the currently active tab receives keyboard focus. Upon initialization of the JavaScript plugin, it sets tabindex="-1" on all inactive tab controls. Once the active tab has focus, the cursor keys activate the previous or next tab. The Home and End keys activate the first and last tabs, respectively. The plugin adjusts the roving tabindex accordingly. However, it is important to note that the JavaScript plugin does not differentiate between horizontal and vertical tab lists regarding cursor key interactions: irrespective of the tab list’s orientation, both the up and left cursor keys navigate to the previous tab, and the down and right cursor keys navigate to the next tab.
tabindex="0" in the markup.A tab or pill navigation can be activated without writing any JavaScript by simply specifying data-bs-toggle="tab" or data-bs-toggle="pill" on an element. These data attributes should be used on .nav-tabs or .nav-pills elements.
HTML
<!-- Nav tabs -->
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item" role="presentation">
<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 class="nav-item" role="presentation">
<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 class="nav-item" role="presentation">
<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 class="nav-item" role="presentation">
<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>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div class="tab-pane active" id="home" role="tabpanel" aria-labelledby="home-tab" tabindex="0"></div>
<div class="tab-pane" id="profile" role="tabpanel" aria-labelledby="profile-tab" tabindex="0"></div>
<div class="tab-pane" id="messages" role="tabpanel" aria-labelledby="messages-tab" tabindex="0"></div>
<div class="tab-pane" id="settings" role="tabpanel" aria-labelledby="settings-tab" tabindex="0"></div>
</div>Tabbable tabs can be enabled via JavaScript (each tab requires individual activation):
const triggerTabList = document.querySelectorAll('#myTab button')
triggerTabList.forEach(triggerEl => {
const tabTrigger = new hummingbird.Tab(triggerEl)
triggerEl.addEventListener('click', event => {
event.preventDefault()
tabTrigger.show()
})
})Individual tabs can be activated in several ways:
const triggerEl = document.querySelector('#myTab button[data-bs-target="#profile"]')
hummingbird.Tab.getInstance(triggerEl).show() // Select tab by name
const triggerFirstTabEl = document.querySelector('#myTab li:first-child button')
hummingbird.Tab.getInstance(triggerFirstTabEl).show() // Select first tabTo incorporate a fade-in effect for tabs, add .fade to each .tab-pane. The initial tab pane must also include .show to ensure its content is visible from the start.
<div class="tab-content">
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab" tabindex="0">...</div>
<div class="tab-pane fade" id="profile" role="tabpanel" aria-labelledby="profile-tab" tabindex="0">...</div>
<div class="tab-pane fade" id="messages" role="tabpanel" aria-labelledby="messages-tab" tabindex="0">...</div>
<div class="tab-pane fade" id="settings" role="tabpanel" aria-labelledby="settings-tab" tabindex="0">...</div>
</div>These methods enable content as a tab element.
A tab instance can be created with the constructor, as demonstrated:
const bsTab = new hummingbird.Tab('#myTab')| Method | Description |
|---|---|
dispose | Destroys an element’s tab functionality. |
getInstance | A static method allowing retrieval of the tab instance associated with a DOM element. Usage: hummingbird.Tab.getInstance(element). |
getOrCreateInstance | A static method that returns an existing tab instance for a DOM element or creates a new one if it has not been initialized. Usage: hummingbird.Tab.getOrCreateInstance(element). |
show | Selects the specified tab and displays its associated pane. Any other tab that was previously selected becomes unselected, and its associated pane is hidden. It returns to the caller before the tab pane has actually been shown (i.e., before the shown.bs.tab event occurs). |
When a new tab is displayed, the events fire in the following sequence:
hide.bs.tab (on the currently active tab)show.bs.tab (on the tab scheduled to be shown)hidden.bs.tab (on the previously active tab, the same as for the hide.bs.tab event)shown.bs.tab (on the newly active, just-shown tab, the same as for the show.bs.tab event)If no tab was previously active, the hide.bs.tab and hidden.bs.tab events will not fire.
| Event Type | Description |
|---|---|
hide.bs.tab | This event fires when a new tab is about to be shown (and thus the previous active tab is about to be hidden). Use event.target and event.relatedTarget to target the current active tab and the new soon-to-be-active tab, respectively. |
hidden.bs.tab | This event fires after a new tab is shown (and thus the previous active tab is hidden). Use event.target and event.relatedTarget to target the previous active tab and the new active tab, respectively. |
show.bs.tab | This event fires upon a tab show, but before the new tab has actually been displayed. Use event.target and event.relatedTarget to target the active tab and the previous active tab (if available), respectively. |
shown.bs.tab | This event fires upon a tab show, after a tab has been displayed. Use event.target and event.relatedTarget to target the active tab and the previous active tab (if available), respectively. |
Example event listener:
const tabEl = document.querySelector('button[data-bs-toggle="tab"]')
tabEl.addEventListener('shown.bs.tab', event => {
event.target // newly activated tab
event.relatedTarget // previous active tab
})