AdminKitDocs
Navigation

React Bootstrap Tabs

React Bootstrap tabs without Bootstrap's JavaScript: TabContainer, TabLink and TabPane switch panes from state, with arrow keys and colored or vertical styles.

Pro

This component is only available in AdminKit PRO. Learn more.

Tabs split related content into panes and show one pane at a time, so a settings page or a project view does not turn into one long scroll. The user clicks a tab, or moves to it with the arrow keys, and its pane appears.

Three React components do the work: TabContainer, TabLink and TabPane. They keep the active tab in React state, so you need neither Bootstrap's JavaScript nor react-bootstrap. They are part of the PRO version of AdminKit for React.

You still write the nav and the panes with Bootstrap's markup. A TabLink and a TabPane with the same eventKey belong together. TabContainer holds the active key. It renders no element of its own, so it does not change your markup. The components are in src/components/bootstrap/tabs.tsx.

Example

import { TabContainer, TabLink, TabPane } from "@/components/bootstrap/tabs";

export function AccountTabs() {
  return (
    <div className="tab">
      <TabContainer defaultActiveKey="profile">
        <ul className="nav nav-tabs" role="tablist">
          <li className="nav-item" role="presentation">
            <TabLink eventKey="profile" className="nav-link">Profile</TabLink>
          </li>
          <li className="nav-item" role="presentation">
            <TabLink eventKey="security" className="nav-link">Security</TabLink>
          </li>
          <li className="nav-item" role="presentation">
            <TabLink eventKey="billing" className="nav-link">Billing</TabLink>
          </li>
        </ul>
        <div className="tab-content">
          <TabPane eventKey="profile">
            <p>Your name, photo and contact details.</p>
          </TabPane>
          <TabPane eventKey="security">
            <p>Your password and two-factor authentication.</p>
          </TabPane>
          <TabPane eventKey="billing">
            <p>Your plan, invoices and payment method.</p>
          </TabPane>
        </div>
      </TabContainer>
    </div>
  );
}

The .tab wrapper gives you AdminKit's tab style: borderless tabs on top of a card-like .tab-content. Leave it out to get Bootstrap's plain .nav-tabs. For pills, use nav nav-pills on the list.

Props

TabContainer:

PropTypeDefaultDescription
defaultActiveKeystringThe tab that is active first
activeKeystringControlled: the active tab; use it with onSelect
onSelect(key: string) => voidCalled with the eventKey of the tab that was selected

TabLink:

PropTypeDefaultDescription
eventKeystringThe key of the pane it shows
asElementType"a"The element: an a with href="#", or "button" (gets type="button")
disabledbooleanAdds .disabled; a click does nothing and the arrow keys skip it

TabPane:

PropTypeDefaultDescription
eventKeystringThe key of its tab
fadebooleantrueFades the pane in (.fade); false switches at once

Other props, such as className and onClick, go to the TabLink and TabPane elements. You do not write the id, aria-controls and aria-labelledby attributes that connect a tab and its pane: they are generated with useId.

Controlled tabs

Sometimes the active tab has to change from outside the nav: a button elsewhere on the page opens a tab, or the URL keeps track of it. Pass activeKey and onSelect, and the parent component owns the active tab:

import { useSearchParams } from "react-router";

export function SettingsTabs() {
  const [params, setParams] = useSearchParams();
  const tab = params.get("tab") ?? "profile";

  return (
    <TabContainer activeKey={tab} onSelect={(key) => setParams({ tab: key })}>
      {/* the nav and the panes */}
    </TabContainer>
  );
}

Colored and vertical tabs

When the tabs should stand out, give them a color. Add a theme color to the wrapper (tab-primary, tab-success, tab-danger, ...) to color the active tab and the content. Add tab-vertical to put the tabs on the left. The demo panes use .tab-title for their headings.

<div className="tab tab-vertical tab-primary">
  <TabContainer defaultActiveKey="general">
    <ul className="nav nav-tabs" role="tablist">
      <li className="nav-item" role="presentation">
        <TabLink eventKey="general" className="nav-link">General</TabLink>
      </li>
      <li className="nav-item" role="presentation">
        <TabLink eventKey="team" className="nav-link">Team</TabLink>
      </li>
    </ul>
    <div className="tab-content">
      <TabPane eventKey="general" fade={false}>
        <h2 className="h4 tab-title">General</h2>
        <p>The name and the time zone of the workspace.</p>
      </TabPane>
      <TabPane eventKey="team" fade={false}>
        <h2 className="h4 tab-title">Team</h2>
        <p>The members of the workspace and their roles.</p>
      </TabPane>
    </div>
  </TabContainer>
</div>

Tabs can also show an icon instead of a label. Put the icon in the TabLink and give the link an aria-label, as the demo does: <TabLink eventKey="settings" className="nav-link" aria-label="Settings"><Settings className="align-middle" /></TabLink>. The .tab style sizes the icon to 20px.

Accessibility

  • TabLink has role="tab", aria-selected and aria-controls. TabPane has role="tabpanel", aria-labelledby and tabIndex={0}. Add role="tablist" to the list and role="presentation" to its items yourself, as in the example.
  • Only the active tab is in the Tab order. Arrow keys, Home and End move to another tab of the same role="tablist" and show its pane, as in Bootstrap 5.3. Without role="tablist" on the list, the arrow keys do nothing.
  • Icon-only tabs need an aria-label.
  • disabled only adds the .disabled class. Add aria-disabled="true" for screen readers.

Last updated on

On this page