Tab List
<quiet-tab-list>
Tab lists let users switch between different sections of content without leaving the page, providing a clean and organized interface.
Tab lists follow the
ARIA APG tooltip pattern
for accessibility. They are comprised of three different components. A single tab list surrounds one or more
tabs and their corresponding
tab panels. Each panel must have a unique name
, and
each tab must have a panel
attribute that maps to a panel.
<quiet-tab-list label="Select a tab"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list>
In the same way that images require alt
text, you should add a label
to every
tab list. The label won't be displayed, but it will be announced by assistive devices.
Examples Jump to heading
Setting the active tab Jump to heading
To make a specific tab show initially, or to programmatically activate a tab, set the
tab
attribute to the name of the desired panel.
<quiet-tab-list label="Select a tab" tab="second"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list>
Showing tabs at the bottom Jump to heading
Set the placement
attribute to bottom
to show tabs at the bottom.
<quiet-tab-list label="Select a tab" placement="bottom"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list>
Showing tabs at the start Jump to heading
Set the placement
attribute to start
to show tabs at the start. The tabs will
automatically move to the opposite side in RTL languages.
<quiet-tab-list label="Select a tab" placement="start"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list>
Showing tabs at the end Jump to heading
Set the placement
attribute to end
to show tabs at the end. The tabs will
automatically move to the opposite side in RTL languages.
<quiet-tab-list label="Select a tab" placement="end"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list>
Scrolling tabs Jump to heading
When the number of tabs exceeds the available space in a top or bottom placement, the tab container will scroll horizontally.
<quiet-tab-list label="Select a tab"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab panel="fourth">Fourth</quiet-tab> <quiet-tab panel="fifth">Fifth</quiet-tab> <quiet-tab panel="sixth">Sixth</quiet-tab> <quiet-tab panel="seventh">Seventh</quiet-tab> <quiet-tab panel="eight">Eight</quiet-tab> <quiet-tab panel="ninth">Ninth</quiet-tab> <quiet-tab panel="tenth">Tenth</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> <quiet-tab-panel name="fourth">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="fifth">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="sixth">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> <quiet-tab-panel name="seventh">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="eight">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="ninth">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> <quiet-tab-panel name="tenth">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> </quiet-tab-list>
If you don't want the tabs to scroll, you can apply flex-wrap: wrap
to the
tabs
part to force them to wrap instead.
Disabling Jump to heading
To disable a tab, add the disabled
attribute to it. Since tabs use
automatic activation, disabled tabs are not focusable but are still recognized by assistive devices as disabled tabs.
<quiet-tab-list label="Select a tab"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second" disabled>Second (disabled)</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list>
Lazy loading content Jump to heading
Quiet considers lazy loading tab content to be an anti-pattern but, when necessary, you can use the
quiet-tab-shown
event to do it.
<quiet-tab-list label="Select a tab" id="tab-list__lazy"> <quiet-tab panel="regular">Regular</quiet-tab> <quiet-tab panel="lazy">Lazy</quiet-tab> <quiet-tab-panel name="regular">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="lazy"> <quiet-spinner label="Loading" style="display: block; margin-inline: auto;"></quiet-spinner> </quiet-tab-panel> </quiet-tab-list> <script> const tabList = document.getElementById('tab-list__lazy'); const lazyPanel = tabList.querySelector('quiet-tab-panel[name="lazy"]'); tabList.addEventListener('quiet-tab-shown', event => { if (event.detail.tab.panel === 'lazy' && !lazyPanel.hasAttribute('data-loaded')) { lazyPanel.setAttribute('data-loaded', ''); // Some async operation... setTimeout(() => { lazyPanel.innerHTML = 'I was loaded after the tab was shown.'; }, 2000); } }); </script>
Making tabs closable Jump to heading
Avoid nesting buttons and other interactive elements inside of a tab, as it will cause assistive devices to work incorrectly. Instead, you can add buttons adjacent to tabs using `. When tabs are removable, you should also listen for the Delete key.
Note that we use tabindex="-1"
on the close button to prevent it from interfering
with normal tabbing. The button, however, is still accessible to virtual cursors.
<quiet-tab-list label="Select a tab" id="tab-list__closable"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-button slot="tab" appearance="text" size="xs" icon-label="Close second tab" tabindex="-1"> <quiet-icon name="x"></quiet-icon> </quiet-button> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list> <quiet-button disabled style="margin-block-start: 2rem;">Restore Tab</quiet-button> <script> const tabList = document.getElementById('tab-list__closable'); const firstTab = tabList.querySelector('quiet-tab[panel="first"]'); const secondTab = tabList.querySelector('quiet-tab[panel="second"]'); const secondPanel = tabList.querySelector('quiet-tab-panel[name="second"]'); const closeButton = tabList.querySelector('quiet-button'); const restoreButton = tabList.nextElementSibling; function closeTab() { closeButton.remove(); secondTab.remove(); secondPanel.remove(); restoreButton.disabled = false; if (tabList.active === 'second') { tabList.active = 'third'; } } function restoreTab() { firstTab.insertAdjacentElement('afterend', closeButton); firstTab.insertAdjacentElement('afterend', secondTab); tabList.append(secondPanel); restoreButton.disabled = true; } // Remove the tab when the close button is clicked closeButton.addEventListener('click', closeTab); // Remove the tab when delete is pressed secondTab.addEventListener('keydown', event => { if (event.key === 'Delete') { closeTab(); } }); // Restore the tab restoreButton.addEventListener('click', restoreTab); </script> <style> #tab-list__closable { quiet-button { position: relative; left: -1rem; font-size: .875rem; margin-inline-end: -.5rem; } quiet-button::part(button) { border-radius: var(--quiet-border-radius); height: 2rem; } } </style>
Styling tab lists Jump to heading
Tab lists come with a simple, minimal appearance. Feel free to customize them with your own styles.
<quiet-tab-list label="Select a tab" class="tab-list__cards"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list> <style> .tab-list__cards { quiet-tab { border: solid 1px var(--quiet-neutral-stroke-softer); border-start-start-radius: var(--quiet-border-radius); border-start-end-radius: var(--quiet-border-radius); color: var(--quiet-text-muted); padding-block: .75rem; margin-inline: 2px; } quiet-tab:first-child { margin-inline-start: 0; } quiet-tab:state(active) { border-bottom-color: var(--quiet-background-color); color: var(--quiet-text-body); } &::part(panels) { border-top-width: 1px; margin-top: -1px; } } </style>
<quiet-tab-list label="Select a tab" class="tab-list__segments"> <quiet-tab panel="first">First</quiet-tab> <quiet-tab panel="second">Second</quiet-tab> <quiet-tab panel="third">Third</quiet-tab> <quiet-tab-panel name="first">Lobortis mattis aliquam faucibus purus in massa tempor. Eu lobortis elementum nibh tellus molestie nunc non blandit. Ultrices sagittis orci a scelerisque purus.</quiet-tab-panel> <quiet-tab-panel name="second">Vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae elementum. Aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices.</quiet-tab-panel> <quiet-tab-panel name="third">Pretium vulputate sapien nec sagittis aliquam malesuada bibendum arcu vitae. Mattis enim ut tellus elementum. Ultrices dui sapien eget mi proin sed libero.</quiet-tab-panel> </quiet-tab-list> <style> .tab-list__segments { &::part(tabs) { justify-content: space-between; background-color: var(--quiet-neutral-fill-softer); border-radius: var(--quiet-border-radius); padding: .25rem; } quiet-tab { flex: 1 1 auto; justify-content: center; border: none; border-radius: calc(var(--quiet-border-radius) * .75); color: var(--quiet-text-muted); padding-inline: 2rem; padding-block: .25rem; transition: 100ms background-color ease, 100ms color ease; } quiet-tab:first-child { margin-inline-start: 0; } quiet-tab:state(active) { border: none; background-color: var(--quiet-background-color); color: var(--quiet-text-body); } &::part(panels) { border: none; padding-block: 1rem; margin: 0; } } </style>
API Jump to heading
Importing Jump to heading
The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.
To manually import <quiet-tab-list>
from the CDN, use the following code.
import 'https://cdn.jsdelivr.net/npm/@quietui/quiet@1.0.0/dist/components/tab-list/tab-list.js';
To manually import <quiet-tab-list>
from npm, use the following code.
import '@quietui/quiet/dist/components/tab-list/tab-list.js';
Slots Jump to heading
Tab List supports the following slots. Learn more about using slots
Name | Description |
---|---|
(default) |
One or more <quiet-tab-panel> elements, each with a name attribute
unique to the tab list.
|
tab
|
One or more <quiet-tab> elements, each with a panel attribute linked
to the name of a tab panel. Note that tabs will automatically apply this slot to
themselves, so you can safely omit slot="tab" in your markup. Also useful for
adding close buttons to tabs.
|
Properties Jump to heading
Tab List has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties
Property / Attribute | Description | Reflects | Type | Default |
---|---|---|---|---|
label
|
An accessible label for the tab list. This won't be shown, but it will be read to assistive devices so you should always include one. |
|
string
|
|
tab
|
The name of the tab panel that's currently active. |
|
string
|
|
placement
|
The placement of tab controls. |
|
'top'
|
'top'
|
Events Jump to heading
Tab List dispatches the following custom events. You can listen to them the same way was native events. Learn more about custom events
Name | Description |
---|---|
quiet-tab-shown |
Emitted after a tab is shown. The event will include a detail object with
tab and panel properties that reference the respective tab and panel
elements.
|
quiet-tab-hidden |
Emitted after a tab is hidden. The event will include a detail object with
tab and panel properties that reference the respective tab and panel
elements.
|
CSS parts Jump to heading
Tab List exposes internal elements that can be styled with CSS using the selectors shown below. Learn more about CSS parts
Name | Description | CSS selector |
---|---|---|
tabs |
The container that holds all of the tabs. |
::part(tabs)
|
panels |
The container that holds all of the tab panels. |
::part(panels)
|
Dependencies Jump to heading
Tab List automatically imports the following elements. Sub-dependencies are also included in this list.