UI components

Tabs

Easily create accessible, fully customizable tab interfaces, with robust focus management and keyboard navigation support.

This is the tab panel for "Recent".

<TabGroup>
  <TabList>
    <Tab target="demo-recent" selected>Recent</Tab>
    <Tab target="demo-popular">Popular</Tab>
    <Tab target="demo-trending">Trending</Tab>
  </TabList>

  <TabPanel id>
    <p>This is the tab panel for <b>"Recent"</b>.</p>
  </TabPanel>

  <TabPanel id="demo-popular" hidden>
    <p>This is the tab panel for <b>"Popular"</b>.</p>
  </TabPanel>

  <TabPanel id="demo-trending" hidden>
    <p>This is the tab panel for <b>"Trending"</b>.</p>
  </TabPanel>
</TabGroup>
.ui-tablist {
  display: flex;
}
.ui-tablist > :not([hidden]) ~ :not([hidden]) {
  margin-left: 0.25rem ;
}
.ui-tablist {
  border-radius: 1rem;
  background-color: rgb(30 58 138 / 0.6);
  padding: 0.5rem;
  color: #111;
}
.ui-tablist > .ui-tab:not([hidden]) ~ .ui-tab:not([hidden]) {
  margin-left: 0.5rem;
}
.ui-tab {
  width: 100%;
  border-radius: 0.5rem;
  color: #222;
  background-color: rgb(255 255 255 / 0.7);
  padding: 0.75rem 0.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.25rem;
}
.ui-tab:focus {
  outline: 2px solid rgb(59 130 246 / 0.8);
  outline-offset: 2px;
}
.ui-tab.ui-selected {
  background-color: white;
  color: black;
}
.ui-tab:hover:not(.ui-selected, .ui-disabled),
.ui-tab:focus:not(.ui-selected, .ui-disabled) {
  background-color: rgb(255 255 255 / 0.8);
}
.ui-tabpanel {
  margin-top: 0.5rem;
  border-radius: 0.75rem;
  background-color: rgb(254 254 254);
  border: 2px solid rgb(59 130 246 / 0.8);
  padding: 0.1rem;
  min-height: 8rem;
  display: flex;
  align-items: center;
  justify-content: center;
}
.ui-tabpanel:focus {
  outline: 2px solid transparent;
  outline-offset: 2px;
}
.ui-tabpanel.ui-hidden {
  display: none;
}

Tabs are built using the TabGroup, TabList, Tab, and TabPanel components. Clicking on any tab or selecting it with the keyboard will activate the corresponding panel.

Styling states

CSS selector Description
.ui-hidden Added to all TabPanel except the one that is active.
.ui-selected Added to the selected Tab.
.ui-disabled Added to disabled Tabs.

Disabling a tab

To disable a tab, use the disabled attribute on the Tab component. Disabled tabs cannot be selected with the mouse, and are also skipped when navigating the tab list using the keyboard.

Manually activating tabs

By default, tabs are automatically selected as the user navigates through them using the arrow kbds.

If you'd rather not change the current tab until the user presses Enter or Space, use the manual attribute on the TabGroup component.

Remember to add styles to the :focus state of the tab so is clear to the user that the tab is focused.

<TabGroup>
  <TabList manual>
    <Tab target="manual-recent" selected>Recent</Tab>
    <Tab target="manual-popular">Popular</Tab>
    <Tab target="manual-disabled" disabled>Disabled</Tab>
    <Tab target="manual-trending">Trending</Tab>
  </TabList>

  <TabPanel id="manual-recent">
    <p>This is the tab panel for <b>"Recent"</b>.</p>
  </TabPanel>

  <TabPanel id="manual-popular" hidden>
    <p>This is the tab panel for <b>"Popular"</b>.</p>
  </TabPanel>

  <TabPanel id="manual-disabled" hidden>
    <p>This is the tab panel for "Disabled".</p>
  </TabPanel>

  <TabPanel id="manual-trending" hidden>
    <p>This is the tab panel for <b>"Trending"</b>.</p>
  </TabPanel>
</TabGroup>

This is the tab panel for "Recent".

This is the tab panel for "Disabled".

The manual prop has no impact on mouse interactions — tabs will still be selected as soon as they are clicked.

Vertical tabs

If you've styled your TabList to appear vertically, use the vertical attribute to enable navigating with the and arrow kbds instead of and , and to update the aria-orientation attribute for assistive technologies.

<TabGroup>
  <TabList vertical>
    <Tab target="vertical-recent" selected>Recent</Tab>
    <Tab target="vertical-popular">Popular</Tab>
    <Tab target="vertical-disabled" disabled>Disabled</Tab>
    <Tab target="vertical-trending">Trending</Tab>
  </TabList>

  <TabPanel id="vertical-recent">
    <p>This is the tab panel for <b>"Recent"</b>.</p>
  </TabPanel>

  <TabPanel id="vertical-popular" hidden>
    <p>This is the tab panel for <b>"Popular"</b>.</p>
  </TabPanel>

  <TabPanel id="vertical-disabled" hidden>
    <p>This is the tab panel for "Disabled".</p>
  </TabPanel>

  <TabPanel id="vertical-trending" hidden>
    <p>This is the tab panel for <b>"Trending"</b>.</p>
  </TabPanel>
</TabGroup>

This is the tab panel for "Recent".

This is the tab panel for "Disabled".

Controlling the tabs with a <select>

Sometimes, you want to display a <select> element in addition to tabs. To do so, use the TabSelect and TabOption components. A TabSelect component is a wrapper for a <select> element, and it accepts TabOption components as children.

Note that a TabSelect is not a replacement for a TabList. For accessibility the TabList must be remain in your code, even if it's visually hidden.

<TabGroup>
  <TabSelect>
    <TabOption target="select-recent">Recent</TabOption>
    <TabOption target="select-popular">Popular</TabOption>
    <TabOption target="select-disabled" disabled>Disabled</TabOption>
    <TabOption target="select-trending">Trending</TabOption>
  </TabSelect>

  <TabList>
    <Tab target="select-recent">Recent</Tab>
    <Tab target="select-popular" selected>Popular</Tab>
    <Tab target="select-disabled" disabled>Disabled</Tab>
    <Tab target="select-trending">Trending</Tab>
  </TabList>

  <TabPanel id="select-recent">
    <p>This is the tab panel for <b>"Recent"</b>.</p>
  </TabPanel>

  <TabPanel id="select-popular" hidden>
    <p>This is the tab panel for <b>"Popular"</b>.</p>
  </TabPanel>

  <TabPanel id="select-disabled" hidden>
    <p>This is the tab panel for "Disabled".</p>
  </TabPanel>

  <TabPanel id="select-trending" hidden>
    <p>This is the tab panel for <b>"Trending"</b>.</p>
  </TabPanel>
</TabGroup>

This is the tab panel for "Recent".

This is the tab panel for "Disabled".

Component arguments

TabGroup

Argument Type Default Description
tag str "div" HTML tag used for rendering the wrapper.

TabList

Argument Type Default Description
vertical bool false Use the and arrow kbds to move between tabs instead of the defaults and arrow kbds.
manual bool false If true, selecting a tab with the keyboard won't activate it, you must press Enter os Space kbds to do it.
tag str "nav" HTML tag used for rendering the wrapper.

Tab

Argument Type Default Description
target str Required. HTML id of the panel associated with this tab.
selected bool false Initially selected tab. Only one tab in the TabList can be selected at the time.
disabled bool false If the tab can be selected.
tag str "button" HTML tag used for rendering the tab.

TabPanel

Argument Type Default Description
hidden bool false Initially hidden panel.
tag bool "div" HTML tag used for rendering the panel.

TabSelect

No arguments.

TabOption

Argument Type Default Description
target str Required. HTML id of the panel associated with this tab.
disabled bool false Display the option but not allow to select it.

Events

A tab emits a jxui:tab:selected event every time is selected. The event contains the target property with the tag node.

document.addEventListener("jxui:tab:selected", (event) => {
  console.log(`'${event.target.textContent}' tab selected`);
});

Accessibility notes

Mouse interaction

Clicking a Tab will select that tab and display the corresponding TabPanel.

Keyboard interaction

All interactions apply when a Tab component is focused.

Command Description
/ arrow kbds Selects the previous/next non-disabled tab, cycling from last to first and vice versa.
/ arrow kbds when vertical is set Selects the previous/next non-disabled tab, cycling from last to first and vice versa.
Enter or Space when manual is set Activates the selected tab
Home or PageUp Activates the first tab
End or PageDown Activates the last tab