Skip to main content
WebsiteGitHub last commitGitHub commit activityGitHub IssuesDocker PullsDiscordLocalized

Working with Tabs in Docusaurus

Tabs are a powerful way to organize related content and provide interactive elements in your documentation. Docusaurus provides built-in tab functionality that's easy to implement and customize.

Basic Tab Implementation

Simple Tabs

Here's the basic syntax for creating tabs in your MDX files:

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

<Tabs>
<TabItem value="apple" label="Apple" default>
This is an apple 🍎
</TabItem>
<TabItem value="orange" label="Orange">
This is an orange 🍊
</TabItem>
<TabItem value="banana" label="Banana">
This is a banana 🍌
</TabItem>
</Tabs>

Result:

This is an apple 🍎

Tabs with Code Examples

Tabs are especially useful for showing different installation methods or code examples:

npm install docusaurus

Advanced Tab Features

Default Tab Selection

There are two ways to set a default tab:

Option 1 — default attribute on <TabItem>:

<Tabs>
<TabItem value="linux" label="Linux" default>
Linux is selected by default.
</TabItem>
<TabItem value="windows" label="Windows">
Windows content here.
</TabItem>
<TabItem value="macos" label="macOS">
macOS content here.
</TabItem>
</Tabs>

Option 2 — defaultValue prop on <Tabs>:

<Tabs defaultValue="windows">
<TabItem value="linux" label="Linux">
Linux content here.
</TabItem>
<TabItem value="windows" label="Windows">
Windows is selected by default.
</TabItem>
<TabItem value="macos" label="macOS">
macOS content here.
</TabItem>
</Tabs>

Result:

Windows is selected by default.

tip

To show no tab selected by default, use defaultValue={null}. Docusaurus will throw an error if defaultValue references a value that doesn't exist in the tab list.

Defining Tabs via values Prop

You can define tab labels and values directly on <Tabs> using the values prop instead of inline TabItem props. When both are present, the Tabs props take precedence.

<Tabs
defaultValue="apple"
values={[
{label: 'Apple', value: 'apple'},
{label: 'Orange', value: 'orange'},
{label: 'Banana', value: 'banana'},
]}>
<TabItem value="apple">This is an apple 🍎</TabItem>
<TabItem value="orange">This is an orange 🍊</TabItem>
<TabItem value="banana">This is a banana 🍌</TabItem>
</Tabs>

Result:

This is an apple 🍎

Lazy Rendering

By default, all tabs are rendered eagerly at build time so search engines can index hidden tab content. To render only the default tab, use <Tabs lazy />:

<Tabs lazy>
<TabItem value="npm" label="npm" default>
npm install
</TabItem>
<TabItem value="yarn" label="Yarn">
yarn install
</TabItem>
</Tabs>

Tab Groups and Syncing

You can sync multiple tab groups across your page using the groupId attribute. When users select a tab in one group, all other groups with the same groupId will automatically switch to the corresponding tab:

<Tabs groupId="operating-systems">
<TabItem value="linux" label="Linux" default>
Use apt or dnf to install packages.
</TabItem>
<TabItem value="windows" label="Windows">
Use winget or choco to install packages.
</TabItem>
<TabItem value="macos" label="macOS">
Use brew to install packages.
</TabItem>
</Tabs>

<Tabs groupId="operating-systems">
<TabItem value="linux" label="Linux" default>
sudo apt install nginx
</TabItem>
<TabItem value="windows" label="Windows">
winget install nginx
</TabItem>
<TabItem value="macos" label="macOS">
brew install nginx
</TabItem>
</Tabs>

Selecting Windows in the first group automatically selects Windows in the second group. The selection is also persisted to localStorage, so it will be remembered on the next visit.

note

If one tab group is switched to a value that doesn't exist in another group sharing the same groupId, that other group will not change. Group IDs are globally namespaced.

Result:

Use apt or dnf to install packages.

sudo apt install nginx

Query String Sync

You can make tab selections persist in the URL by using the queryString prop. This lets users share links that open on a specific tab:

<Tabs queryString="package-manager">
<TabItem value="npm" label="npm" default>
npm install
</TabItem>
<TabItem value="yarn" label="Yarn">
yarn install
</TabItem>
<TabItem value="pnpm" label="pnpm">
pnpm install
</TabItem>
</Tabs>

Selecting Yarn appends ?package-manager=yarn to the URL. Visiting that URL will pre-select the Yarn tab. Note that this does not create an anchor link — the browser will not scroll to the tab.

Result:

npm install

tip

queryString can be combined with groupId. When queryString is set to true (without a string value), the groupId is used as the query parameter name. The URL query string takes priority over localStorage when the page loads.

<Tabs groupId="current-os" queryString>
<TabItem value="android" label="Android">Android</TabItem>
<TabItem value="ios" label="iOS">iOS</TabItem>
</Tabs>

Customizing Tabs

className Prop

Add a CSS class directly to the <Tabs> wrapper element using the className prop:

<Tabs className="unique-tabs">
<TabItem value="apple">This is an apple 🍎</TabItem>
<TabItem value="orange">This is an orange 🍊</TabItem>
<TabItem value="banana">This is a banana 🍌</TabItem>
</Tabs>

This adds unique-tabs to the container so you can target it with CSS:

src/css/custom.css
.unique-tabs .tabs__item {
font-weight: bold;
}

attributes Prop on TabItem

Customize individual tab headings using the attributes prop on <TabItem>. This is useful for adding CSS Module classes or data-* attributes to specific tabs:

some-doc.mdx
import styles from './styles.module.css';

<Tabs>
<TabItem value="apple" label="Apple" attributes={{className: styles.red}}>
This is an apple 🍎
</TabItem>
<TabItem value="orange" label="Orange" attributes={{className: styles.orange}}>
This is an orange 🍊
</TabItem>
<TabItem value="banana" label="Banana" attributes={{className: styles.yellow}}>
This is a banana 🍌
</TabItem>
</Tabs>
styles.module.css
.red { color: red; }
.red[aria-selected='true'] { border-bottom-color: red; }

.orange { color: orange; }
.orange[aria-selected='true'] { border-bottom-color: orange; }

.yellow { color: yellow; }
.yellow[aria-selected='true'] { border-bottom-color: yellow; }
tip

You can also use a data-value field and target it with a CSS attribute selector:

li[role='tab'][data-value='apple'] {
color: red;
}

Styling Tabs

Custom CSS for Tabs

You can customize tab appearance by adding CSS to your src/css/custom.css file:

/* Tab navigation styling */
.tabs {
border: 1px solid var(--ifm-color-emphasis-300);
border-radius: 8px;
overflow: hidden;
}

.tabs__item {
background: var(--ifm-background-color);
border-right: 1px solid var(--ifm-color-emphasis-300);
transition: background-color 0.2s ease;
}

.tabs__item:hover {
background: var(--ifm-color-emphasis-100);
}

.tabs__item--active {
background: var(--ifm-color-primary);
color: white;
}

/* Tab content styling */
.tab-content {
padding: 1rem;
background: var(--ifm-background-surface-color);
}

Dark Mode Considerations

Ensure your tab styling works well in both light and dark modes:

[data-theme='dark'] .tabs__item {
background: var(--ifm-background-color);
border-color: var(--ifm-color-emphasis-200);
}

[data-theme='dark'] .tabs__item--active {
background: var(--ifm-color-primary-dark);
}

Best Practices

Content Organization

  • Related Content: Use tabs for content that's mutually exclusive but related (like different OS instructions)
  • Logical Grouping: Keep similar content types together
  • Clear Labels: Use descriptive, concise tab labels

User Experience

  • Default Selection: Always specify a sensible default tab
  • Consistent Ordering: Keep the same tab order across different tab groups
  • Mobile Consideration: Ensure tabs work well on mobile devices

Common Use Cases

Installation Instructions

Perfect for showing different installation methods:

docker run -d \
--name=nextcloud \
-p 80:80 \
nextcloud:latest

Configuration Examples

Show different configuration options:

version: '3'
services:
app:
image: nginx
ports:
- "80:80"

Troubleshooting

Common Issues

  1. Tabs not rendering: Ensure you've imported the required components
  2. Styling issues: Check that your custom CSS doesn't conflict with Docusaurus styles
  3. Sync not working: Verify that groupId values match exactly across tab groups

Debug Tips

  • Use browser developer tools to inspect tab elements
  • Check the console for any JavaScript errors
  • Verify that MDX syntax is correct (proper indentation, closed tags)

Resources

Buy me a beer

Changelog

docs(tabs): add advanced tab examples from official Docusaurus docs
Update MDX syntax to follow Docusaurus best practices
Fix MDX compilation with React Fragments - Build now successful!
Fix MDX compilation errors by properly escaping JSX tags in code examples
Add comprehensive Docusaurus styling documentation


💬 Discord Community Chat

Join the conversation! Comments here sync with our Discord community.

💬 Recent Comments

Loading comments...