Warning
This is an internal project, and is not intended for public use. No support or stability guarantees are provided.
A rehype plugin that transforms code identifiers into clickable anchor links, allowing users to navigate to type documentation by clicking on type references in code snippets.
The enhanceCodeExportLinks plugin scans syntax-highlighted code for type names and converts matching spans into anchor links. It supports both inline <code> elements and code blocks within <pre> elements, and handles dotted chains like Accordion.Trigger.State.
Component.Root.Props as a single anchorpl-c1 (constants) and pl-en (entity names/types)This plugin is part of @mui/internal-docs-infra and doesn't need separate installation.
import { unified } from 'unified';
import rehypeParse from 'rehype-parse';
import rehypeStringify from 'rehype-stringify';
import enhanceCodeExportLinks from '@mui/internal-docs-infra/pipeline/enhanceCodeExportLinks';
const anchorMap = {
Trigger: '#trigger',
'Accordion.Trigger': '#trigger',
'Accordion.Trigger.Props': '#trigger.props',
};
const processor = unified()
.use(rehypeParse, { fragment: true })
.use(enhanceCodeExportLinks, { anchorMap })
.use(rehypeStringify);
const result = await processor.process('<code><span class="pl-en">Trigger</span></code>');
console.log(String(result));
// Output: <code><a href="#trigger" class="pl-en">Trigger</a></code>
This plugin is typically used with abstractCreateTypes to link type references to their documentation:
import enhanceCodeExportLinks from '@mui/internal-docs-infra/pipeline/enhanceCodeExportLinks';
// The anchorMap is automatically generated from your type exports
const anchorMap = {
Root: '#root',
'Accordion.Root': '#root',
'Accordion.Root.Props': '#root.props',
'Accordion.Trigger': '#trigger',
AccordionTrigger: '#trigger', // Flat name mapping
};
// Used as a rehype enhancer in type processing
const enhancers = [[enhanceCodeExportLinks, { anchorMap }]];
<!-- Input (after syntax highlighting) -->
<code><span class="pl-en">InputType</span></code>
<!-- Output -->
<code><a href="#inputtype" class="pl-en">InputType</a></code>
<!-- Input -->
<code><span class="pl-c1">Trigger</span></code>
<!-- Output -->
<code><a href="#trigger" class="pl-c1">Trigger</a></code>
<!-- Input -->
<code><span class="pl-en">Accordion</span>.<span class="pl-en">Trigger</span></code>
<!-- Output -->
<code
><a href="#trigger"
><span class="pl-en">Accordion</span>.<span class="pl-en">Trigger</span></a
></code
>
<!-- Input -->
<code
><span class="pl-en">Component</span>.<span class="pl-en">Root</span>.<span class="pl-en"
>ChangeEventDetails</span
></code
>
<!-- Output -->
<code
><a href="#root.changeeventdetails"
><span class="pl-en">Component</span>.<span class="pl-en">Root</span>.<span class="pl-en"
>ChangeEventDetails</span
></a
></code
>
Code blocks with frame/line spans are processed recursively:
<!-- Input -->
<code class="language-ts">
<span class="frame">
<span class="line"> <span class="pl-en">Component</span>.<span class="pl-en">Root</span> </span>
</span>
</code>
<!-- Output -->
<code class="language-ts">
<span class="frame">
<span class="line">
<a href="#root"><span class="pl-en">Component</span>.<span class="pl-en">Root</span></a>
</span>
</span>
</code>
<!-- Input -->
<code><span class="pl-en">TypeA</span> and <span class="pl-en">TypeB</span></code>
<!-- Output -->
<code><a href="#typea" class="pl-en">TypeA</a> and <a href="#typeb" class="pl-en">TypeB</a></code>
The plugin looks for these patterns in code elements:
<span> with class pl-c1 or pl-en containing a type name. text nodesSingle span:
span.pl-en("Trigger") → a.pl-en[href="#trigger"]("Trigger")
Dotted chain:
span.pl-en("Accordion") + text(".") + span.pl-en("Trigger")
↓
a[href="#trigger"](span.pl-en("Accordion") + "." + span.pl-en("Trigger"))
The anchorMap is a Record<string, string> that maps type names to anchor hrefs:
const anchorMap = {
// Direct type names
Root: '#root',
Trigger: '#trigger',
// Dotted names (full namespace)
'Accordion.Root': '#root',
'Accordion.Trigger': '#trigger',
'Accordion.Trigger.Props': '#trigger.props',
// Flat names (for backward compatibility)
AccordionRoot: '#root',
AccordionTrigger: '#trigger',
};
The plugin recursively processes nested elements (like frame and line spans) to find linkable spans at any depth, making it work with both simple inline code and complex code block structures.
Types not in the anchor map are left unchanged:
<!-- Input -->
<code><span class="pl-en">UnknownType</span></code>
<!-- anchorMap: { Trigger: '#trigger' } -->
<!-- Output: unchanged -->
<code><span class="pl-en">UnknownType</span></code>
Matching is case-sensitive:
<!-- Input -->
<code><span class="pl-en">trigger</span></code>
<!-- anchorMap: { Trigger: '#trigger' } -->
<!-- Output: unchanged (case doesn't match) -->
<code><span class="pl-en">trigger</span></code>
Only exact chain matches are linked:
<!-- Input -->
<code><span class="pl-en">Accordion</span>.<span class="pl-en">Unknown</span></code>
<!-- anchorMap: { 'Accordion.Trigger': '#trigger' } -->
<!-- Output: unchanged (chain doesn't match) -->
<code><span class="pl-en">Accordion</span>.<span class="pl-en">Unknown</span></code>
Spans separated by text other than . are treated as separate matches:
<!-- Input -->
<code><span class="pl-en">Accordion</span>: <span class="pl-en">Trigger</span></code>
<!-- anchorMap: { Accordion: '#accordion', Trigger: '#trigger' } -->
<!-- Output: linked separately -->
<code
><a href="#accordion" class="pl-en">Accordion</a>:
<a href="#trigger" class="pl-en">Trigger</a></code
>
When used with loadPrecomputedTypes, the anchor map is automatically generated from your type exports:
// Generated automatically from your types
const anchorMap = buildAnchorMap(exports, additionalTypes, typeNameMap);
// {
// 'Root': '#root',
// 'Accordion.Root': '#root',
// 'Accordion.Root.Props': '#root.props',
// 'AccordionRoot': '#root', // from typeNameMap
// }
Each type in the processed output includes a slug property that matches the anchor:
{
type: 'component',
name: 'Accordion.Trigger',
slug: 'trigger', // Used for <details id="trigger">
data: { /* ... */ }
}
This plugin should run after syntax highlighting plugins:
transformHtmlCodeInlineHighlighted - Applies syntax highlightingenhanceCodeExportLinks - Links type references (this plugin)enhanceCodeInlineElements - Consolidates tag bracketsRunning it earlier would prevent the pattern from matching since the highlighting spans wouldn't exist yet.
Options for the enhanceCodeExportLinks plugin.
type EnhanceCodeExportLinksOptions = { anchorMap: Record<string, string> };