| title | Code Tabs Plugin | |||||
|---|---|---|---|---|---|---|
| description | Display code examples in multiple languages with interactive tabbed interface | |||||
| section | Plugins | |||||
| difficulty | beginner | |||||
| tags |
|
Display code examples in multiple languages with an interactive tabbed interface.
tab: JavaScript
---
```javascript
import { tabsPlugin } from '@goobits/docs-engine/plugins';
export default {
preprocess: [
mdsvex({
remarkPlugins: [
tabsPlugin(),
// ... other plugins
],
}),
],
};
```
---
tab: TypeScript
---
```typescript
import { mdsvex } from 'mdsvex';
import { tabsPlugin } from '@goobits/docs-engine/plugins';
import type { Config } from '@sveltejs/kit';
const config: Config = {
preprocess: [
mdsvex({
remarkPlugins: [
tabsPlugin(),
// ... other plugins
],
}),
],
};
export default config;
```
<script>
import { CodeTabsHydrator } from '@goobits/docs-engine/components';
</script>
<CodeTabsHydrator theme="dracula" />
<slot />Use a code fence with tabs:id as the language, then define tabs with tab: Label markers:
````tabs:hello-world
tab: JavaScript
---
```js
console.log('Hello World');
```
---
tab: TypeScript
---
```ts
const message: string = 'Hello World';
console.log(message);
```
---
tab: Python
---
```py
print('Hello World')
```
````````tabs:unique-id
tab: Tab Label 1
---
```language
code here
```
---
tab: Tab Label 2
---
```language
more code
```
````- Tabs ID:
tabs:unique-id- Must be unique per page - Tab Marker:
tab: Label- Defines tab name - Separator:
---- Separates tabs and sections - Code Block: Standard markdown code fence with language
- Multiple Tabs: Repeat tab markers and code blocks
````tabs:api-request
tab: cURL
---
```bash
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-d '{"name": "John", "email": "john@example.com"}'
```
---
tab: JavaScript
---
```js
const response = await fetch('https://api.example.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
name: 'John',
email: 'john@example.com'
})
});
const data = await response.json();
```
---
tab: Python
---
```py
import requests
response = requests.post(
'https://api.example.com/users',
json={'name': 'John', 'email': 'john@example.com'}
)
data = response.json()
```
````````tabs:config-examples
tab: JavaScript
---
```js
// JavaScript config
export default {
name: 'my-app',
version: '1.0.0',
dependencies: {
svelte: '^4.0.0'
}
};
```
---
tab: TypeScript
---
```ts
// TypeScript config
import type { Config } from './types';
const config: Config = {
name: 'my-app',
version: '1.0.0',
dependencies: {
svelte: '^4.0.0'
}
};
export default config;
```
---
tab: JSON
---
```json
{
"name": "my-app",
"version": "1.0.0",
"dependencies": {
"svelte": "^4.0.0"
}
}
```
---
tab: YAML
---
```yaml
name: my-app
version: 1.0.0
dependencies:
svelte: ^4.0.0
```
````````tabs:install-commands
tab: npm
---
```bash
npm install @goobits/docs-engine
npm run dev
```
---
tab: pnpm
---
```bash
pnpm add @goobits/docs-engine
pnpm dev
```
---
tab: yarn
---
```bash
yarn add @goobits/docs-engine
yarn dev
```
---
tab: bun
---
```bash
bun add @goobits/docs-engine
bun dev
```
````````tabs:function-example
tab: JavaScript
---
```js
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(10)); // 55
```
---
tab: TypeScript
---
```ts
function fibonacci(n: number): number {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
console.log(fibonacci(10)); // 55
```
---
tab: Python
---
```py
def fibonacci(n: int) -> int:
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(10)) # 55
```
---
tab: Rust
---
```rust
fn fibonacci(n: u32) -> u32 {
if n <= 1 {
return n;
}
fibonacci(n - 1) + fibonacci(n - 2)
}
fn main() {
println!("{}", fibonacci(10)); // 55
}
```
````Language identifiers in code fences determine syntax highlighting:
```ts // ← TypeScript highlighting
```py // ← Python highlighting- Click to switch - Mouse or touch
- Keyboard navigation - Arrow keys to navigate
- Persistent selection - Selected tab remembered across page loads (per tabs-id)
- Deep linking - URL hash support for specific tabs
Works seamlessly with the code highlighting plugin. All code inside tabs receives proper syntax highlighting automatically.
- Touch-friendly tab buttons
- Horizontal scroll for many tabs
- Optimized for small screens
Each tabs group needs a unique ID:
```tabs:config-1 ← Unique ID
```tabs:api-example ← Different ID
```tabs:setup-steps ← Another unique IDImportant
IDs must be unique per page to avoid conflicts!
Labels can be any text:
tab: JavaScript
tab: TypeScript (Recommended)
tab: Python 3.11+
tab: cURL ExampleSupport all languages that Shiki supports (100+):
- JavaScript, TypeScript, JSX, TSX
- Python, Ruby, PHP, Go, Rust
- Bash, PowerShell, Shell
- JSON, YAML, TOML, XML
- CSS, SCSS, LESS
- SQL, GraphQL
- And many more!
Tabs render with semantic classes:
<div class="md-code-tabs" data-tabs-id="example" data-tabs="...">
<div class="md-code-tabs__nav">
<button class="md-code-tabs__tab md-code-tabs__tab--active">
JavaScript
</button>
<button class="md-code-tabs__tab">
TypeScript
</button>
</div>
<div class="md-code-tabs__content">
<!-- Code content here -->
</div>
</div>.md-code-tabs- Container.md-code-tabs__nav- Tab navigation.md-code-tabs__tab- Individual tab button.md-code-tabs__tab--active- Active tab state.md-code-tabs__content- Content area
.md-code-tabs {
border-radius: 8px;
overflow: hidden;
margin: 1.5rem 0;
}
.md-code-tabs__nav {
background: var(--color-surface);
border-bottom: 2px solid var(--color-border);
display: flex;
gap: 0.5rem;
padding: 0.5rem;
}
.md-code-tabs__tab {
padding: 0.75rem 1.5rem;
border: none;
border-radius: 6px;
background: transparent;
cursor: pointer;
transition: background 0.2s;
}
.md-code-tabs__tab:hover {
background: var(--color-hover);
}
.md-code-tabs__tab--active {
background: var(--color-primary);
color: white;
}Too few: Users miss options Too many: UI becomes cluttered
✅ Good: JavaScript, TypeScript, Python
✅ Good: npm, pnpm, yarn, bun
❌ Too many: JS, TS, Python, Ruby, PHP, Go, Rust, JavaEach tab should show the same functionality in different languages:
✅ Good: All tabs fetch user data
❌ Bad: Tab 1 fetches users, Tab 2 creates users, Tab 3 deletes usersPut most common language first:
✅ Good: JavaScript → TypeScript → Python
❌ Bad: Rust → Haskell → JavaScriptFull, working examples are better than snippets:
✅ Good: Complete API call with error handling
❌ Bad: Just `fetch(url)` without contextUse consistent naming across your docs:
✅ Good: "JavaScript" everywhere
❌ Bad: "JavaScript", "JS", "ECMAScript", "Node.js"Show different package managers:
````tabs:install
tab: npm
---
```bash
npm install package-namepnpm add package-name```
### API Examples
Show different programming languages:
```markdown
````tabs:api
tab: JavaScript
---
```js
await fetch('/api/data')
```
---
tab: Python
---
```py
requests.get('/api/data')
```
### Configuration Formats
Show different config file formats:
```markdown
````tabs:config
tab: JSON
---
```json
{ "key": "value" }
key: value```
### Framework Comparisons
Show same feature in different frameworks:
```markdown
````tabs:frameworks
tab: React
---
```jsx
const [count, setCount] = useState(0);
```
---
tab: Vue
---
```vue
const count = ref(0);
```
---
tab: Svelte
---
```svelte
let count = 0;
```
---
## Troubleshooting
> [!QUESTION] Tabs not rendering?
>
> **Check:**
> 1. Plugin added to MDSveX config: `tabsPlugin()`
> 2. Hydrator imported in layout: `<CodeTabsHydrator />`
> 3. Syntax is correct: ` ```tabs:id ` (not `:::tabs`)
> 4. Tab markers present: `tab: Label`
> 5. Separators present: `---`
> [!QUESTION] Tabs ID must be unique?
>
> Yes! Each tabs group needs a unique ID. Duplicate IDs will cause conflicts.
>
> ```markdown
> ````tabs:example-1 ✅ Unique
> ````tabs:example-2 ✅ Different
> ````tabs:example-1 ❌ Duplicate!
> ```
> [!QUESTION] Can I nest tabs?
>
> No, tabs cannot be nested inside other tabs. Keep structure flat.
> [!QUESTION] Syntax highlighting not working?
>
> Ensure `codeHighlightPlugin()` runs **after** `tabsPlugin()` in your plugin order:
>
> ```js
> remarkPlugins: [
> tabsPlugin(),
> // ... other plugins
> codeHighlightPlugin(), // ← Must be last
> ]
> ```
---
## Accessibility
Tabs include accessibility features:
- `role="tablist"` - Tab navigation
- `role="tab"` - Individual tabs
- `role="tabpanel"` - Content panels
- `aria-selected` - Active tab state
- `aria-controls` - Tab-to-panel relationships
- Keyboard navigation (Arrow keys, Home, End)
---
## Related Documentation
**Prerequisites:** Basic markdown knowledge, code highlighting setup
**Next Steps:**
- [Code Highlighting](./code-highlighting.md) - Syntax highlighting with Shiki
- [Collapse Plugin](./collapse.md) - Collapsible sections
**Related:**
- [Plugin Order](../guides/plugin-order.md) - Understanding plugin execution
- [Examples Guide](../guides/examples.md) - More code examples