Skip to main content
Since Shoelace 2.0 Code stable Pattern stable Figma ready

Tab Group

<sl-tab-group> | SlTabGroup

Tab groups organize content into a container that shows one section at a time.

Examples

Basic Tab Group

Tab groups make use of tabs and tab panels. Each tab must be slotted into the nav slot and its panel must refer to a tab panel of the same name.

General Custom Advanced Disabled This is the general tab panel. This is the custom tab panel. This is the advanced tab panel. This is a disabled tab panel.
<sl-tab-group>
  <sl-tab slot="nav" panel="general">General</sl-tab>
  <sl-tab slot="nav" panel="custom">Custom</sl-tab>
  <sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
  <sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>

  <sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
  <sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
  <sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
  <sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
sl-tab-group
  sl-tab slot="nav" panel="general" General
  sl-tab slot="nav" panel="custom" Custom
  sl-tab slot="nav" panel="advanced" Advanced
  sl-tab slot="nav" panel="disabled" disabled="true" Disabled
  sl-tab-panel name="general" This is the general tab panel.
  sl-tab-panel name="custom" This is the custom tab panel.
  sl-tab-panel name="advanced" This is the advanced tab panel.
  sl-tab-panel name="disabled" This is a disabled tab panel.
import SlTab from '@teamshares/shoelace/dist/react/tab';
import SlTabGroup from '@teamshares/shoelace/dist/react/tab-group';
import SlTabPanel from '@teamshares/shoelace/dist/react/tab-panel';

const App = () => (
  <SlTabGroup>
    <SlTab slot="nav" panel="general">
      General
    </SlTab>
    <SlTab slot="nav" panel="custom">
      Custom
    </SlTab>
    <SlTab slot="nav" panel="advanced">
      Advanced
    </SlTab>
    <SlTab slot="nav" panel="disabled" disabled>
      Disabled
    </SlTab>

    <SlTabPanel name="general">This is the general tab panel.</SlTabPanel>
    <SlTabPanel name="custom">This is the custom tab panel.</SlTabPanel>
    <SlTabPanel name="advanced">This is the advanced tab panel.</SlTabPanel>
    <SlTabPanel name="disabled">This is a disabled tab panel.</SlTabPanel>
  </SlTabGroup>
);

Tabs with Badges

Use badges in tabs to show counts of items.

Emails Notes You have 1,200 unread emails. You have 10 unread notes.
<sl-tab-group>
  <sl-tab slot="nav" panel="emails">Emails
    <sl-badge value=1200>
  </sl-tab>
  <sl-tab slot="nav" panel="notes">Notes
    <sl-badge value=10>
  </sl-tab>

  <sl-tab-panel name="emails">You have 1,200 unread emails.</sl-tab-panel>
  <sl-tab-panel name="notes">You have 10 unread notes.</sl-tab-panel>
</sl-tab-group>
sl-tab-group
  sl-tab slot="nav" panel="emails" Emails
    sl-badge value=1200
  sl-tab slot="nav" panel="notes" Notes
    sl-badge value=10
  sl-tab-panel name="emails" You have 1,200 unread emails.
  sl-tab-panel name="notes" You have 10 unread notes.

Closable Tabs

Add the closable attribute to a tab to show a close button. This example shows how you can dynamically remove tabs from the DOM when the close button is activated.

General Closable 1 Closable 2 Closable 3 This is the general tab panel. This is the first closable tab panel. This is the second closable tab panel. This is the third closable tab panel.
<sl-tab-group class="tabs-closable">
  <sl-tab slot="nav" panel="general">General</sl-tab>
  <sl-tab slot="nav" panel="closable-1" closable>Closable 1</sl-tab>
  <sl-tab slot="nav" panel="closable-2" closable>Closable 2</sl-tab>
  <sl-tab slot="nav" panel="closable-3" closable>Closable 3</sl-tab>

  <sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
  <sl-tab-panel name="closable-1">This is the first closable tab panel.</sl-tab-panel>
  <sl-tab-panel name="closable-2">This is the second closable tab panel.</sl-tab-panel>
  <sl-tab-panel name="closable-3">This is the third closable tab panel.</sl-tab-panel>
</sl-tab-group>

<script>
  const tabGroup = document.querySelector('.tabs-closable');

  tabGroup.addEventListener('sl-close', async event => {
    const tab = event.target;
    const panel = tabGroup.querySelector(`sl-tab-panel[name="${tab.panel}"]`);

    // Show the previous tab if the tab is currently active
    if (tab.active) {
      tabGroup.show(tab.previousElementSibling.panel);
    }

    // Remove the tab + panel
    tab.remove();
    panel.remove();
  });
</script>
sl-tab-group.tabs-closable
  sl-tab slot="nav" panel="general" General
  sl-tab slot="nav" panel="closable-1" closable="true" Closable 1
  sl-tab slot="nav" panel="closable-2" closable="true" Closable 2
  sl-tab slot="nav" panel="closable-3" closable="true" Closable 3
  sl-tab-panel name="general" This is the general tab panel.
  sl-tab-panel name="closable-1" This is the first closable tab panel.
  sl-tab-panel name="closable-2" This is the second closable tab panel.
  sl-tab-panel name="closable-3" This is the third closable tab panel.

javascript:
  const tabGroup = document.querySelector(.tabs-closable);

  tabGroup.addEventListener(sl-close, async event => {
    const tab = event.target;
    const panel = tabGroup.querySelector(`sl-tab-panel[name="${tab.panel}"]`);

    // Show the previous tab if the tab is currently active
    if (tab.active) {
      tabGroup.show(tab.previousElementSibling.panel);
    }

    // Remove the tab + panel
    tab.remove();
    panel.remove();
  });
import SlTab from '@teamshares/shoelace/dist/react/tab';
import SlTabGroup from '@teamshares/shoelace/dist/react/tab-group';
import SlTabPanel from '@teamshares/shoelace/dist/react/tab-panel';

const App = () => {
  function handleClose(event) {
    //
    // This is a crude example that removes the tab and its panel from the DOM.
    // There are better ways to manage tab creation/removal in React, but that
    // would significantly complicate the example.
    //
    const tab = event.target;
    const tabGroup = tab.closest('sl-tab-group');
    const tabPanel = tabGroup.querySelector(`[aria-labelledby="${tab.id}"]`);

    tab.remove();
    tabPanel.remove();
  }

  return (
    <SlTabGroup className="tabs-closable" onSlClose={handleClose}>
      <SlTab slot="nav" panel="general">
        General
      </SlTab>
      <SlTab slot="nav" panel="closable-1" closable onSlClose={handleClose}>
        Closable 1
      </SlTab>
      <SlTab slot="nav" panel="closable-2" closable onSlClose={handleClose}>
        Closable 2
      </SlTab>
      <SlTab slot="nav" panel="closable-3" closable onSlClose={handleClose}>
        Closable 3
      </SlTab>

      <SlTabPanel name="general">This is the general tab panel.</SlTabPanel>
      <SlTabPanel name="closable-1">This is the first closable tab panel.</SlTabPanel>
      <SlTabPanel name="closable-2">This is the second closable tab panel.</SlTabPanel>
      <SlTabPanel name="closable-3">This is the third closable tab panel.</SlTabPanel>
    </SlTabGroup>
  );
};

Scrolling Tabs

When there are more tabs than horizontal space allows, the nav will be scrollable.

Tab 1 Tab 2 Tab 3 Tab 4 Tab 5 Tab 6 Tab 7 Tab 8 Tab 9 Tab 10 Tab 11 Tab 12 Tab 13 Tab 14 Tab 15 Tab 16 Tab 17 Tab 18 Tab 19 Tab 20 Tab panel 1 Tab panel 2 Tab panel 3 Tab panel 4 Tab panel 5 Tab panel 6 Tab panel 7 Tab panel 8 Tab panel 9 Tab panel 10 Tab panel 11 Tab panel 12 Tab panel 13 Tab panel 14 Tab panel 15 Tab panel 16 Tab panel 17 Tab panel 18 Tab panel 19 Tab panel 20
<sl-tab-group>
  <sl-tab slot="nav" panel="tab-1">Tab 1</sl-tab>
  <sl-tab slot="nav" panel="tab-2">Tab 2</sl-tab>
  <sl-tab slot="nav" panel="tab-3">Tab 3</sl-tab>
  <sl-tab slot="nav" panel="tab-4">Tab 4</sl-tab>
  <sl-tab slot="nav" panel="tab-5">Tab 5</sl-tab>
  <sl-tab slot="nav" panel="tab-6">Tab 6</sl-tab>
  <sl-tab slot="nav" panel="tab-7">Tab 7</sl-tab>
  <sl-tab slot="nav" panel="tab-8">Tab 8</sl-tab>
  <sl-tab slot="nav" panel="tab-9">Tab 9</sl-tab>
  <sl-tab slot="nav" panel="tab-10">Tab 10</sl-tab>
  <sl-tab slot="nav" panel="tab-11">Tab 11</sl-tab>
  <sl-tab slot="nav" panel="tab-12">Tab 12</sl-tab>
  <sl-tab slot="nav" panel="tab-13">Tab 13</sl-tab>
  <sl-tab slot="nav" panel="tab-14">Tab 14</sl-tab>
  <sl-tab slot="nav" panel="tab-15">Tab 15</sl-tab>
  <sl-tab slot="nav" panel="tab-16">Tab 16</sl-tab>
  <sl-tab slot="nav" panel="tab-17">Tab 17</sl-tab>
  <sl-tab slot="nav" panel="tab-18">Tab 18</sl-tab>
  <sl-tab slot="nav" panel="tab-19">Tab 19</sl-tab>
  <sl-tab slot="nav" panel="tab-20">Tab 20</sl-tab>

  <sl-tab-panel name="tab-1">Tab panel 1</sl-tab-panel>
  <sl-tab-panel name="tab-2">Tab panel 2</sl-tab-panel>
  <sl-tab-panel name="tab-3">Tab panel 3</sl-tab-panel>
  <sl-tab-panel name="tab-4">Tab panel 4</sl-tab-panel>
  <sl-tab-panel name="tab-5">Tab panel 5</sl-tab-panel>
  <sl-tab-panel name="tab-6">Tab panel 6</sl-tab-panel>
  <sl-tab-panel name="tab-7">Tab panel 7</sl-tab-panel>
  <sl-tab-panel name="tab-8">Tab panel 8</sl-tab-panel>
  <sl-tab-panel name="tab-9">Tab panel 9</sl-tab-panel>
  <sl-tab-panel name="tab-10">Tab panel 10</sl-tab-panel>
  <sl-tab-panel name="tab-11">Tab panel 11</sl-tab-panel>
  <sl-tab-panel name="tab-12">Tab panel 12</sl-tab-panel>
  <sl-tab-panel name="tab-13">Tab panel 13</sl-tab-panel>
  <sl-tab-panel name="tab-14">Tab panel 14</sl-tab-panel>
  <sl-tab-panel name="tab-15">Tab panel 15</sl-tab-panel>
  <sl-tab-panel name="tab-16">Tab panel 16</sl-tab-panel>
  <sl-tab-panel name="tab-17">Tab panel 17</sl-tab-panel>
  <sl-tab-panel name="tab-18">Tab panel 18</sl-tab-panel>
  <sl-tab-panel name="tab-19">Tab panel 19</sl-tab-panel>
  <sl-tab-panel name="tab-20">Tab panel 20</sl-tab-panel>
</sl-tab-group>
sl-tab-group
  sl-tab slot="nav" panel="tab-1" Tab 1
  sl-tab slot="nav" panel="tab-2" Tab 2
  sl-tab slot="nav" panel="tab-3" Tab 3
  sl-tab slot="nav" panel="tab-4" Tab 4
  sl-tab slot="nav" panel="tab-5" Tab 5
  sl-tab slot="nav" panel="tab-6" Tab 6
  sl-tab slot="nav" panel="tab-7" Tab 7
  sl-tab slot="nav" panel="tab-8" Tab 8
  sl-tab slot="nav" panel="tab-9" Tab 9
  sl-tab slot="nav" panel="tab-10" Tab 10
  sl-tab slot="nav" panel="tab-11" Tab 11
  sl-tab slot="nav" panel="tab-12" Tab 12
  sl-tab slot="nav" panel="tab-13" Tab 13
  sl-tab slot="nav" panel="tab-14" Tab 14
  sl-tab slot="nav" panel="tab-15" Tab 15
  sl-tab slot="nav" panel="tab-16" Tab 16
  sl-tab slot="nav" panel="tab-17" Tab 17
  sl-tab slot="nav" panel="tab-18" Tab 18
  sl-tab slot="nav" panel="tab-19" Tab 19
  sl-tab slot="nav" panel="tab-20" Tab 20
  sl-tab-panel name="tab-1" Tab panel 1
  sl-tab-panel name="tab-2" Tab panel 2
  sl-tab-panel name="tab-3" Tab panel 3
  sl-tab-panel name="tab-4" Tab panel 4
  sl-tab-panel name="tab-5" Tab panel 5
  sl-tab-panel name="tab-6" Tab panel 6
  sl-tab-panel name="tab-7" Tab panel 7
  sl-tab-panel name="tab-8" Tab panel 8
  sl-tab-panel name="tab-9" Tab panel 9
  sl-tab-panel name="tab-10" Tab panel 10
  sl-tab-panel name="tab-11" Tab panel 11
  sl-tab-panel name="tab-12" Tab panel 12
  sl-tab-panel name="tab-13" Tab panel 13
  sl-tab-panel name="tab-14" Tab panel 14
  sl-tab-panel name="tab-15" Tab panel 15
  sl-tab-panel name="tab-16" Tab panel 16
  sl-tab-panel name="tab-17" Tab panel 17
  sl-tab-panel name="tab-18" Tab panel 18
  sl-tab-panel name="tab-19" Tab panel 19
  sl-tab-panel name="tab-20" Tab panel 20
import SlTab from '@teamshares/shoelace/dist/react/tab';
import SlTabGroup from '@teamshares/shoelace/dist/react/tab-group';
import SlTabPanel from '@teamshares/shoelace/dist/react/tab-panel';

const App = () => (
  <SlTabGroup>
    <SlTab slot="nav" panel="tab-1">
      Tab 1
    </SlTab>
    <SlTab slot="nav" panel="tab-2">
      Tab 2
    </SlTab>
    <SlTab slot="nav" panel="tab-3">
      Tab 3
    </SlTab>
    <SlTab slot="nav" panel="tab-4">
      Tab 4
    </SlTab>
    <SlTab slot="nav" panel="tab-5">
      Tab 5
    </SlTab>
    <SlTab slot="nav" panel="tab-6">
      Tab 6
    </SlTab>
    <SlTab slot="nav" panel="tab-7">
      Tab 7
    </SlTab>
    <SlTab slot="nav" panel="tab-8">
      Tab 8
    </SlTab>
    <SlTab slot="nav" panel="tab-9">
      Tab 9
    </SlTab>
    <SlTab slot="nav" panel="tab-10">
      Tab 10
    </SlTab>
    <SlTab slot="nav" panel="tab-11">
      Tab 11
    </SlTab>
    <SlTab slot="nav" panel="tab-12">
      Tab 12
    </SlTab>
    <SlTab slot="nav" panel="tab-13">
      Tab 13
    </SlTab>
    <SlTab slot="nav" panel="tab-14">
      Tab 14
    </SlTab>
    <SlTab slot="nav" panel="tab-15">
      Tab 15
    </SlTab>
    <SlTab slot="nav" panel="tab-16">
      Tab 16
    </SlTab>
    <SlTab slot="nav" panel="tab-17">
      Tab 17
    </SlTab>
    <SlTab slot="nav" panel="tab-18">
      Tab 18
    </SlTab>
    <SlTab slot="nav" panel="tab-19">
      Tab 19
    </SlTab>
    <SlTab slot="nav" panel="tab-20">
      Tab 20
    </SlTab>

    <SlTabPanel name="tab-1">Tab panel 1</SlTabPanel>
    <SlTabPanel name="tab-2">Tab panel 2</SlTabPanel>
    <SlTabPanel name="tab-3">Tab panel 3</SlTabPanel>
    <SlTabPanel name="tab-4">Tab panel 4</SlTabPanel>
    <SlTabPanel name="tab-5">Tab panel 5</SlTabPanel>
    <SlTabPanel name="tab-6">Tab panel 6</SlTabPanel>
    <SlTabPanel name="tab-7">Tab panel 7</SlTabPanel>
    <SlTabPanel name="tab-8">Tab panel 8</SlTabPanel>
    <SlTabPanel name="tab-9">Tab panel 9</SlTabPanel>
    <SlTabPanel name="tab-10">Tab panel 10</SlTabPanel>
    <SlTabPanel name="tab-11">Tab panel 11</SlTabPanel>
    <SlTabPanel name="tab-12">Tab panel 12</SlTabPanel>
    <SlTabPanel name="tab-13">Tab panel 13</SlTabPanel>
    <SlTabPanel name="tab-14">Tab panel 14</SlTabPanel>
    <SlTabPanel name="tab-15">Tab panel 15</SlTabPanel>
    <SlTabPanel name="tab-16">Tab panel 16</SlTabPanel>
    <SlTabPanel name="tab-17">Tab panel 17</SlTabPanel>
    <SlTabPanel name="tab-18">Tab panel 18</SlTabPanel>
    <SlTabPanel name="tab-19">Tab panel 19</SlTabPanel>
    <SlTabPanel name="tab-20">Tab panel 20</SlTabPanel>
  </SlTabGroup>
);

Manual Activation

When focused, keyboard users can press Left or Right to select the desired tab. By default, the corresponding tab panel will be shown immediately (automatic activation). You can change this behavior by setting activation="manual" which will require the user to press Space or Enter before showing the tab panel (manual activation).

General Custom Advanced Disabled This is the general tab panel. This is the custom tab panel. This is the advanced tab panel. This is a disabled tab panel.
<sl-tab-group activation="manual">
  <sl-tab slot="nav" panel="general">General</sl-tab>
  <sl-tab slot="nav" panel="custom">Custom</sl-tab>
  <sl-tab slot="nav" panel="advanced">Advanced</sl-tab>
  <sl-tab slot="nav" panel="disabled" disabled>Disabled</sl-tab>

  <sl-tab-panel name="general">This is the general tab panel.</sl-tab-panel>
  <sl-tab-panel name="custom">This is the custom tab panel.</sl-tab-panel>
  <sl-tab-panel name="advanced">This is the advanced tab panel.</sl-tab-panel>
  <sl-tab-panel name="disabled">This is a disabled tab panel.</sl-tab-panel>
</sl-tab-group>
sl-tab-group activation="manual"
  sl-tab slot="nav" panel="general" General
  sl-tab slot="nav" panel="custom" Custom
  sl-tab slot="nav" panel="advanced" Advanced
  sl-tab slot="nav" panel="disabled" disabled="true" Disabled
  sl-tab-panel name="general" This is the general tab panel.
  sl-tab-panel name="custom" This is the custom tab panel.
  sl-tab-panel name="advanced" This is the advanced tab panel.
  sl-tab-panel name="disabled" This is a disabled tab panel.
import SlTab from '@teamshares/shoelace/dist/react/tab';
import SlTabGroup from '@teamshares/shoelace/dist/react/tab-group';
import SlTabPanel from '@teamshares/shoelace/dist/react/tab-panel';

const App = () => (
  <SlTabGroup activation="manual">
    <SlTab slot="nav" panel="general">
      General
    </SlTab>
    <SlTab slot="nav" panel="custom">
      Custom
    </SlTab>
    <SlTab slot="nav" panel="advanced">
      Advanced
    </SlTab>
    <SlTab slot="nav" panel="disabled" disabled>
      Disabled
    </SlTab>

    <SlTabPanel name="general">This is the general tab panel.</SlTabPanel>
    <SlTabPanel name="custom">This is the custom tab panel.</SlTabPanel>
    <SlTabPanel name="advanced">This is the advanced tab panel.</SlTabPanel>
    <SlTabPanel name="disabled">This is a disabled tab panel.</SlTabPanel>
  </SlTabGroup>
);

Importing

If you’re using the autoloader or the traditional loader, you can ignore this section. Otherwise, feel free to use any of the following snippets to cherry pick this component.

Script Import Bundler React

To import this component from the CDN using a script tag:

<script type="module" src="https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.1.0/cdn/components/tab-group/tab-group.js"></script>

To import this component from the CDN using a JavaScript import:

import 'https://cdn.jsdelivr.net/npm/@shoelace-style/shoelace@2.1.0/cdn/components/tab-group/tab-group.js';

To import this component using a bundler:

import '@shoelace-style/shoelace/dist/components/tab-group/tab-group.js';

To import this component as a React component:

import SlTabGroup from '@shoelace-style/shoelace/dist/react/tab-group';

Slots

Name Description
(default) Used for grouping tab panels in the tab group. Must be <sl-tab-panel> elements.
nav Used for grouping tabs in the tab group. Must be <sl-tab> elements.

Learn more about using slots.

Properties

Name Description Reflects Type Default
placement The placement of the tabs. 'top' | 'bottom' | 'start' | 'end' 'top'
activation When set to auto, navigating tabs with the arrow keys will instantly show the corresponding tab panel. When set to manual, the tab will receive focus but will not show until the user presses spacebar or enter. 'auto' | 'manual' 'auto'
noScrollControls
no-scroll-controls
Disables the scroll arrows that appear when tabs overflow. boolean false
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
sl-tab-show onSlTabShow Emitted when a tab is shown. { name: String }
sl-tab-hide onSlTabHide Emitted when a tab is hidden. { name: String }

Learn more about events.

Methods

Name Description Arguments
show() Shows the specified tab panel. panel: string

Learn more about methods.

Custom Properties

Name Description Default
--indicator-color The color of the active tab indicator.
--track-color The color of the indicator’s track (the line that separates tabs from panels).
--track-width The width of the indicator’s track (the line that separates tabs from panels).

Learn more about customizing CSS custom properties.

Parts

Name Description
base The component’s base wrapper.
nav The tab group’s navigation container where tabs are slotted in.
tabs The container that wraps the tabs.
active-tab-indicator The line that highlights the currently selected tab.
body The tab group’s body where tab panels are slotted in.
scroll-button The previous/next scroll buttons that show when tabs are scrollable, an <sl-icon-button>.
scroll-button--start The starting scroll button.
scroll-button--end The ending scroll button.
scroll-button__base The scroll button’s exported base part.

Learn more about customizing CSS parts.

Dependencies

This component automatically imports the following dependencies.

  • <sl-icon>
  • <sl-icon-button>