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:
- Apple
- Orange
- Banana
This is an apple 🍎
This is an orange 🍊
This is a banana 🍌
Tabs with Code Examples
Tabs are especially useful for showing different installation methods or code examples:
- npm
- Yarn
- pnpm
npm install docusaurus
yarn add docusaurus
pnpm add 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:
- Linux
- Windows
- macOS
Linux content here.
Windows is selected by default.
macOS content here.
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:
- Apple
- Orange
- Banana
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.
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:
- Linux
- Windows
- macOS
Use apt or dnf to install packages.
Use winget or choco to install packages.
Use brew to install packages.
- Linux
- Windows
- macOS
sudo apt install nginx
winget install nginx
brew 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
- Yarn
- pnpm
npm install
yarn install
pnpm install
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:
.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:
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>
.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; }
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
- Manual
docker run -d \
--name=nextcloud \
-p 80:80 \
nextcloud:latest
# Download and extract
wget https://download.nextcloud.com/server/releases/latest.tar.bz2
tar -xjf latest.tar.bz2
Configuration Examples
Show different configuration options:
- Basic Config
- Advanced Config
version: '3'
services:
app:
image: nginx
ports:
- "80:80"
version: '3'
services:
app:
image: nginx
ports:
- "80:80"
environment:
- SSL_ENABLED=true
volumes:
- ./config:/etc/nginx/conf.d
Troubleshooting
Common Issues
- Tabs not rendering: Ensure you've imported the required components
- Styling issues: Check that your custom CSS doesn't conflict with Docusaurus styles
- Sync not working: Verify that
groupIdvalues 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
- Official Docusaurus Tabs Documentation
- MDX Documentation - For understanding MDX syntax
- Infima CSS Framework - The CSS framework used by Docusaurus
- React Tabs Component - For understanding the underlying React concepts
💬 Recent Comments