Codegroup
Display code blocks with terminal-style chrome. Multiple fences become a tabbed view with language-based tab names. A single fence without labels renders as a clean code block with just the chrome — no tabs.
Basic usage
Tabs are automatically labeled by their code block language.
{% codegroup %}
```js
const x = 1;
```
```python
x = 1
```
{% /codegroup %}<section data-rune="code-group">
<div role="tablist" data-name="tabs">
<button data-name="tab" role="tab">
<span>JavaScript</span>
</button>
<button data-name="tab" role="tab">
<span>Python</span>
</button>
</div>
<div data-name="panels">
<div role="tabpanel" data-name="panel">
<div class="rf-codeblock">
<pre data-language="js">
<code data-language="js">const x = 1;
</code>
</pre>
</div>
</div>
<div role="tabpanel" data-name="panel">
<div class="rf-codeblock">
<pre data-language="python">
<code data-language="python">x = 1
</code>
</pre>
</div>
</div>
</div>
</section>const x = 1;
x = 1
<section class="rf-codegroup rf-codegroup--scroll" data-overflow="scroll" data-rune="code-group" data-density="compact">
<div data-name="topbar" class="rf-codegroup__topbar" data-section="header">
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
</div>
<div role="tablist" data-name="tabs" class="rf-codegroup__tabs">
<button data-name="tab" role="tab" class="rf-codegroup__tab">
<span>JavaScript</span>
</button>
<button data-name="tab" role="tab" class="rf-codegroup__tab">
<span>Python</span>
</button>
</div>
<div data-name="panels" class="rf-codegroup__panels">
<div role="tabpanel" data-name="panel" class="rf-codegroup__panel">
<div class="rf-codeblock">
<pre data-language="js"><code data-language="js">const x = 1;
</code></pre>
</div>
</div>
<div role="tabpanel" data-name="panel" class="rf-codegroup__panel">
<div class="rf-codeblock">
<pre data-language="python"><code data-language="python">x = 1
</code></pre>
</div>
</div>
</div>
</section>Custom labels
Use the labels attribute to override the default language-based tab names. Useful when multiple tabs share the same language.
{% codegroup labels="React, Vue, Svelte" %}
```jsx
export default function App() {
return <h1>Hello</h1>;
}
```
```html
<template>
<h1>Hello</h1>
</template>
```
```html
<h1>Hello</h1>
```
{% /codegroup %}<section data-rune="code-group">
<div role="tablist" data-name="tabs">
<button data-name="tab" role="tab">
<span>React</span>
</button>
<button data-name="tab" role="tab">
<span>Vue</span>
</button>
<button data-name="tab" role="tab">
<span>Svelte</span>
</button>
</div>
<div data-name="panels">
<div role="tabpanel" data-name="panel">
<div class="rf-codeblock">
<pre data-language="jsx">
<code data-language="jsx">export default function App() {
return <h1>Hello</h1>;
}
</code>
</pre>
</div>
</div>
<div role="tabpanel" data-name="panel">
<div class="rf-codeblock">
<pre data-language="html">
<code data-language="html"><template>
<h1>Hello</h1>
</template>
</code>
</pre>
</div>
</div>
<div role="tabpanel" data-name="panel">
<div class="rf-codeblock">
<pre data-language="html">
<code data-language="html"><h1>Hello</h1>
</code>
</pre>
</div>
</div>
</div>
</section>export default function App() {
return <h1>Hello</h1>;
}
<template>
<h1>Hello</h1>
</template>
<h1>Hello</h1>
<section class="rf-codegroup rf-codegroup--scroll" data-overflow="scroll" data-rune="code-group" data-density="compact">
<div data-name="topbar" class="rf-codegroup__topbar" data-section="header">
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
</div>
<div role="tablist" data-name="tabs" class="rf-codegroup__tabs">
<button data-name="tab" role="tab" class="rf-codegroup__tab">
<span>React</span>
</button>
<button data-name="tab" role="tab" class="rf-codegroup__tab">
<span>Vue</span>
</button>
<button data-name="tab" role="tab" class="rf-codegroup__tab">
<span>Svelte</span>
</button>
</div>
<div data-name="panels" class="rf-codegroup__panels">
<div role="tabpanel" data-name="panel" class="rf-codegroup__panel">
<div class="rf-codeblock">
<pre data-language="jsx"><code data-language="jsx">export default function App() {
return <h1>Hello</h1>;
}
</code></pre>
</div>
</div>
<div role="tabpanel" data-name="panel" class="rf-codegroup__panel">
<div class="rf-codeblock">
<pre data-language="html"><code data-language="html"><template>
<h1>Hello</h1>
</template>
</code></pre>
</div>
</div>
<div role="tabpanel" data-name="panel" class="rf-codegroup__panel">
<div class="rf-codeblock">
<pre data-language="html"><code data-language="html"><h1>Hello</h1>
</code></pre>
</div>
</div>
</div>
</section>With title
Use the title attribute to display a filename or label in the topbar. With a single code fence and no labels, the codegroup renders as chrome-only — the topbar and code block without any tabs.
{% codegroup title="app.js" %}
```js
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
```
{% /codegroup %}<section data-rune="code-group">
<meta content="app.js" data-field="title">
<div class="rf-codeblock">
<pre data-language="js">
<code data-language="js">import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
</code>
</pre>
</div>
</section>import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
<section class="rf-codegroup rf-codegroup--scroll" data-title="app.js" data-overflow="scroll" data-rune="code-group" data-density="compact">
<div data-name="topbar" class="rf-codegroup__topbar" data-section="header">
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="title" class="rf-codegroup__title" data-section="title">app.js</span>
</div>
<div class="rf-codeblock">
<pre data-language="js"><code data-language="js">import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
</code></pre>
</div>
</section>To force a tab bar on a single fence, provide the labels attribute.
{% codegroup title="server" labels="Express" %}
```js
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
```
{% /codegroup %}<section data-rune="code-group">
<meta content="server" data-field="title">
<div role="tablist" data-name="tabs">
<button data-name="tab" role="tab">
<span>Express</span>
</button>
</div>
<div data-name="panels">
<div role="tabpanel" data-name="panel">
<div class="rf-codeblock">
<pre data-language="js">
<code data-language="js">import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
</code>
</pre>
</div>
</div>
</div>
</section>import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
<section class="rf-codegroup rf-codegroup--scroll" data-title="server" data-overflow="scroll" data-rune="code-group" data-density="compact">
<div data-name="topbar" class="rf-codegroup__topbar" data-section="header">
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="title" class="rf-codegroup__title" data-section="title">server</span>
</div>
<div role="tablist" data-name="tabs" class="rf-codegroup__tabs">
<button data-name="tab" role="tab" class="rf-codegroup__tab">
<span>Express</span>
</button>
</div>
<div data-name="panels" class="rf-codegroup__panels">
<div role="tabpanel" data-name="panel" class="rf-codegroup__panel">
<div class="rf-codeblock">
<pre data-language="js"><code data-language="js">import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.send('Hello World');
});
</code></pre>
</div>
</div>
</div>
</section>Overflow control
Use the overflow attribute to control how long lines are handled. The default is scroll (horizontal scrollbar). Use wrap to wrap lines, or hide to clip without a scrollbar.
{% codegroup overflow="wrap" title="wrapped.ts" %}
```ts
const result = await fetchUserDataFromRemoteService(userId, { includeMetadata: true, resolveReferences: true, maxDepth: 3, timeout: 5000 });
```
{% /codegroup %}<section data-rune="code-group">
<meta content="wrapped.ts" data-field="title">
<meta content="wrap" data-field="overflow">
<div class="rf-codeblock">
<pre data-language="ts">
<code data-language="ts">const result = await fetchUserDataFromRemoteService(userId, { includeMetadata: true, resolveReferences: true, maxDepth: 3, timeout: 5000 });
</code>
</pre>
</div>
</section>const result = await fetchUserDataFromRemoteService(userId, { includeMetadata: true, resolveReferences: true, maxDepth: 3, timeout: 5000 });
<section class="rf-codegroup rf-codegroup--wrap" data-title="wrapped.ts" data-overflow="wrap" data-rune="code-group" data-density="compact">
<div data-name="topbar" class="rf-codegroup__topbar" data-section="header">
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="dot" class="rf-codegroup__dot"></span>
<span data-name="title" class="rf-codegroup__title" data-section="title">wrapped.ts</span>
</div>
<div class="rf-codeblock">
<pre data-language="ts"><code data-language="ts">const result = await fetchUserDataFromRemoteService(userId, { includeMetadata: true, resolveReferences: true, maxDepth: 3, timeout: 5000 });
</code></pre>
</div>
</section>Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
labels | string | — | Comma-separated custom tab names |
title | string | — | Filename or label shown in the topbar |
overflow | string | scroll | Line overflow: scroll, wrap, or hide |
Common attributes
All block runes share these attributes for layout and theming.
| Attribute | Type | Default | Description |
|---|---|---|---|
width | string | content | Page grid width: content, wide, or full |
spacing | string | — | Vertical spacing: flush, tight, default, loose, or breathe |
inset | string | — | Horizontal padding: flush, tight, default, loose, or breathe |
tint | string | — | Named colour tint from theme configuration |
tint-mode | string | auto | Colour scheme override: auto, dark, or light |
bg | string | — | Named background preset from theme configuration |