MDX Notes
How to use Tabs and TabItem in Docusaurus MDX — switching between code languages, OS instructions, package managers, and more
import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';
Tabs let you show multiple versions of the same thing — different languages, different operating systems, different package managers — in one clean, switchable block. Your readers click what's relevant to them and ignore the rest.
Basic Tab Usage
Import the components and wrap your content:
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="js" label="JavaScript">console.log('Hello from JavaScript!');
</TabItem>
<TabItem value="py" label="Python">print("Hello from Python!")
</TabItem>
<TabItem value="rust" label="Rust">fn main() { println!("Hello from Rust!"); }
</TabItem>
</Tabs>Visual Result: Three tab buttons labeled "JavaScript", "Python", and "Rust" appear above a content area. Clicking a tab reveals the corresponding code block while hiding others. The active tab has a highlighted underline/background.
TabItem Component Props
Each TabItem takes a few props:
<TabItem
value="unique-id" {/* Required: unique identifier */}
label="Display Name" {/* Tab button text */}
default {/* Make this the initially active tab */}
attributes={{ {/* HTML attributes for the tab button */}
className: 'custom-tab',
id: 'my-tab',
}}
>
Tab content here
</TabItem>Props Reference
| Prop | Type | Required | Description |
|---|---|---|---|
value | string | ✅ | Unique identifier for the tab |
label | string | ❌ | Display text (falls back to value) |
default | boolean | ❌ | Initially selected tab |
attributes | object | ❌ | HTML attributes for tab button |
Setting the Default Tab
First TabItem is active by default. Want a different one? Add default:
<Tabs>
<TabItem value="windows" label="Windows">
Windows instructions...
</TabItem>
<TabItem value="macos" label="macOS" default>
macOS instructions (shown first)...
</TabItem>
<TabItem value="linux" label="Linux">
Linux instructions...
</TabItem>
</Tabs>Or use defaultValue on the Tabs wrapper:
<Tabs defaultValue="macos">
<TabItem value="windows" label="Windows">...</TabItem>
<TabItem value="macos" label="macOS">...</TabItem>
<TabItem value="linux" label="Linux">...</TabItem>
</Tabs>Synced Tabs with groupId
This is the killer feature. groupId syncs tab selections across your entire page — and even across pages via localStorage:
{/* First set of tabs */}
<Tabs groupId="operating-systems">
<TabItem value="windows" label="Windows">
Download the `.exe` installer from the releases page.
</TabItem>
<TabItem value="macos" label="macOS">
Install via Homebrew: `brew install myapp`
</TabItem>
</Tabs>
{/* Second set of tabs — stays synced with the first! */}
<Tabs groupId="operating-systems">
<TabItem value="windows" label="Windows">
Run the installer and follow the wizard.
</TabItem>
<TabItem value="macos" label="macOS">
The app is now available in your PATH.
</TabItem>
</Tabs>Visual Result: When a user clicks "macOS" in the first tab group, the second tab group automatically switches to "macOS" as well. The selection persists across page navigations because it's stored in localStorage.
:::tip[User Experience] Use groupId whenever you have multiple tab groups on a page (or across pages) that represent the same choice. Users only need to select their preference once — it persists throughout their session and even across visits. :::
Common groupId Patterns
{/* Package managers */}
<Tabs groupId="package-manager">
<TabItem value="npm" label="npm">...</TabItem>
<TabItem value="yarn" label="Yarn">...</TabItem>
<TabItem value="pnpm" label="pnpm">...</TabItem>
</Tabs>
{/* Programming languages */}
<Tabs groupId="language">
<TabItem value="js" label="JavaScript">...</TabItem>
<TabItem value="ts" label="TypeScript">...</TabItem>
</Tabs>
{/* Operating systems */}
<Tabs groupId="os">
<TabItem value="win" label="Windows">...</TabItem>
<TabItem value="mac" label="macOS">...</TabItem>
<TabItem value="linux" label="Linux">...</TabItem>
</Tabs>Lazy Loading Tabs
By default, all tab content renders in the DOM but stays hidden with CSS. If you've got heavy content in some tabs, enable lazy loading so they only render on click:
<Tabs lazy>
<TabItem value="simple" label="Simple Example">
This loads immediately (it's the default tab).
</TabItem>
<TabItem value="complex" label="Complex Visualization">
{/* This heavy component only renders when the tab is clicked */}
<HeavyChartComponent data={largeDataset} />
</TabItem>
<TabItem value="interactive" label="Interactive Demo">
{/* This iframe only loads on demand */}
<iframe src="https://demo.example.com" height="400" />
</TabItem>
</Tabs>:::caution[Lazy Loading Trade-off] Lazy-loaded tabs won't be indexed by search engines since the content isn't in the initial DOM. Use lazy loading only for heavy interactive content, not for text-based documentation. :::
Tabs with Code Blocks
This is the most common use case — showing code in multiple languages or configs:
<Tabs>
<TabItem value="config-basic" label="Basic Config">module.exports = { title: 'My Site', url: 'https://example.com', baseUrl: '/', };
</TabItem>
<TabItem value="config-full" label="Full Config">module.exports = { title: 'My Site', url: 'https://example.com', baseUrl: '/', onBrokenLinks: 'throw', onBrokenMarkdownLinks: 'warn', favicon: 'img/favicon.ico', organizationName: 'my-org', projectName: 'my-project', presets: [ ['classic', { docs: { sidebarPath: './sidebars.js' }, blog: { showReadingTime: true }, theme: { customCss: './src/css/custom.css' }, }], ], };
</TabItem>
</Tabs>:::note[Important Spacing] Always leave a blank line between the <TabItem> tag and your Markdown content (including code blocks). Without this blank line, MDX won't process the Markdown syntax correctly. :::
Custom Tab Styling
CSS Customization
Adding Icons to Tabs
Emoji in the label works great:
<Tabs>
<TabItem value="npm" label="📦 npm" default>npm install @docusaurus/core
</TabItem>
<TabItem value="yarn" label="🧶 Yarn">yarn add @docusaurus/core
</TabItem>
<TabItem value="pnpm" label="⚡ pnpm">pnpm add @docusaurus/core
</TabItem>
</Tabs>Custom Tab Component with Attributes
You can also pass inline styles and classes per tab:
<Tabs className="unique-tabs">
<TabItem
value="react"
label="React"
attributes={{ className: 'react-tab', style: { color: '#61dafb' } }}
>
React content here
</TabItem>
<TabItem
value="vue"
label="Vue"
attributes={{ className: 'vue-tab', style: { color: '#42b883' } }}
>
Vue content here
</TabItem>
</Tabs>Query String Integration
Want the tab selection to show up in the URL so people can share a direct link to their choice?
<Tabs queryString="platform">
<TabItem value="ios" label="iOS">
iOS-specific instructions...
</TabItem>
<TabItem value="android" label="Android">
Android-specific instructions...
</TabItem>
</Tabs>When someone selects "Android", the URL becomes ?platform=android. Share that link and the recipient sees Android pre-selected.
Best Practices
:::tip[Tab Guidelines]
- Keep tab counts reasonable — 2-5 tabs works best; more becomes unwieldy
- Use consistent values — The same
valueandgroupIdacross pages keeps sync working - Always include a default — Don't leave users guessing which tab to pick
- Match content structure — Tabs within a group should have parallel content
- Use groupId liberally — Sync related tab groups so users only choose once
- Prefer labels over values — Make
labelhuman-readable;valuecan be a short ID - Test mobile layouts — Tabs wrap on small screens; keep labels concise
:::
Complete Example: Installation Guide
Here's a real-world example combining multiple tab features:
## Installation
<Tabs groupId="pkg" queryString="pkg">
<TabItem value="npm" label="npm" default>npm init docusaurus@latest my-site classic cd my-site npm start
</TabItem>
<TabItem value="yarn" label="Yarn">yarn create docusaurus my-site classic cd my-site yarn start
</TabItem>
<TabItem value="pnpm" label="pnpm">pnpm create docusaurus my-site classic cd my-site pnpm start
</TabItem>
</Tabs>
Your site is now running at `http://localhost:3000` 🎉Tabs turn long, repetitive docs into something scannable. Pair them with groupId and your readers only pick their preference once — then every tab on your site follows.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Tabs Component in Docusaurus.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this MDX Tutorial topic.
Search Terms
mdx-tutorial, mdx tutorial, mdx, tutorial, docusaurus, tabs, tabs component in docusaurus
Related MDX Tutorial Topics