Code & DataCodegroup

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" data-code-host="true">
  <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 &lt;h1&gt;Hello&lt;/h1&gt;;
}
</code>
        </pre>
      </div>
    </div>
    <div role="tabpanel" data-name="panel">
      <div class="rf-codeblock">
        <pre data-language="html">
          <code data-language="html">&lt;template&gt;
  &lt;h1&gt;Hello&lt;/h1&gt;
&lt;/template&gt;
</code>
        </pre>
      </div>
    </div>
    <div role="tabpanel" data-name="panel">
      <div class="rf-codeblock">
        <pre data-language="html">
          <code data-language="html">&lt;h1&gt;Hello&lt;/h1&gt;
</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" data-code-host="true">
  <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 &lt;h1&gt;Hello&lt;/h1&gt;;
}
</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">&lt;template&gt;
  &lt;h1&gt;Hello&lt;/h1&gt;
&lt;/template&gt;
</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">&lt;h1&gt;Hello&lt;/h1&gt;
</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" data-rune-fields="{&quot;title&quot;:&quot;app.js&quot;}">
  <div class="rf-codeblock">
    <pre data-language="js">
      <code data-language="js">import express from 'express';

const app = express();
app.get('/', (req, res) =&gt; {
  res.send('Hello World');
});
</code>
    </pre>
  </div>
</section>
app.js
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" data-code-host="true">
  <div data-name="topbar" data-zone="topbar" data-zone-layout="bar" class="rf-codegroup__topbar" data-section="header">
    <span data-meta-type="code">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) =&gt; {
  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" data-rune-fields="{&quot;title&quot;:&quot;server&quot;}">
  <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) =&gt; {
  res.send('Hello World');
});
</code>
        </pre>
      </div>
    </div>
  </div>
</section>
server
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" data-code-host="true">
  <div data-name="topbar" data-zone="topbar" data-zone-layout="bar" class="rf-codegroup__topbar" data-section="header">
    <span data-meta-type="code">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) =&gt; {
  res.send('Hello World');
});
</code></pre>
      </div>
    </div>
  </div>
</section>

Tab labels from fence annotations

When neither labels= nor a per-fence label annotation is set, codegroup derives each tab label from the fence's source annotation — automatically populated when the panel is a {% snippet %}, and authorable on hand-written fences. SPEC-062 / WORK-304.

{% codegroup %}
{% snippet path="packages/runes/src/lang-map.ts" lines="3-7" linenumbers=true highlight="4-5" /%}
{% snippet path="packages/runes/src/tags/codegroup.ts" lines="7-14" linenumbers=true highlight="8-9" /%}
{% /codegroup %}

Renders with tabs lang-map.ts:3-7 and codegroup.ts:7-14, each panel's gutter starting at the file's real line offset (3 and 7 respectively), and each panel's highlight range emphasized — all four annotations (source, lines, linenumbers, highlight) propagate through the snippet → fence → codegroup chain uniformly:

 *
 * Shared across the snippet rune, the inspect tool, the contracts generator,
 * and any future rune that needs to infer a syntax-highlighting language
 * from a file extension. Lives in `@refrakt-md/runes` (not in a plugin)
 * because every consumer already depends on this package and plugins
const languageNames: Record<string, string> = {
  js: 'JavaScript', ts: 'TypeScript', py: 'Python',
  rb: 'Ruby', rs: 'Rust', go: 'Go', sh: 'Shell',
  bash: 'Bash', zsh: 'Zsh', shell: 'Shell',
  html: 'HTML', css: 'CSS', json: 'JSON', yaml: 'YAML',
  sql: 'SQL', swift: 'Swift', kt: 'Kotlin', java: 'Java',
  cpp: 'C++', c: 'C', cs: 'C#', php: 'PHP',
};

The label resolution chain (first match wins):

  1. Group-level labels= — positional override (labels="A, B, C").
  2. Per-fence label annotation```ts {% label="SiteConfig" %}.
  3. Derived from source — basename of the path, with :lines suffix when lines= is also set (e.g. theme.ts:74-125).
  4. Prettified language name — today's default (JavaScript, Python, etc.).

Same composition story snippet has elsewhere, just propagated through the fence-annotation surface.

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" data-rune-fields="{&quot;title&quot;:&quot;wrapped.ts&quot;,&quot;overflow&quot;:&quot;wrap&quot;}">
  <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>
wrapped.ts
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" data-code-host="true">
  <div data-name="topbar" data-zone="topbar" data-zone-layout="bar" class="rf-codegroup__topbar" data-section="header">
    <span data-meta-type="code">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

AttributeTypeDefaultDescription
labelsstringComma-separated custom tab names
titlestringFilename or label shown in the topbar
overflowstringscrollLine overflow: scroll, wrap, or hide

Common attributes

All block runes share these attributes for layout and theming.

AttributeTypeDefaultDescription
widthstringcontentPage grid width: content, wide, or full
spacingstringVertical spacing: flush, tight, default, loose, or breathe
insetstringHorizontal padding: flush, tight, default, loose, or breathe
tintstringNamed colour tint from theme configuration
tint-modestringautoColour scheme override: auto, dark, or light
bgstringNamed background preset from theme configuration