Shipping a remark plugin
src/remark/starterRemarkPlugin.ts shows the pattern for bundling a remarkremark A markdown processor. Remark plugins transform the markdown AST before it becomes HTML/JSX. plugin with your Docusaurus plugin. This lets you transform markdown at build time — useful for custom shortcodes, auto-linking (like the glossary plugin), or syntax extensions.
The shape of a remark plugin
import type { Plugin } from 'unified';
import type { Root } from 'mdast';
import { visit } from 'unist-util-visit';
export interface StarterRemarkOptions {
marker?: string;
replacement?: string;
}
export const createStarterRemarkPlugin =
(options: StarterRemarkOptions = {}): Plugin<[], Root> =>
() =>
(tree) => {
const marker = options.marker ?? 'NOTE';
const replacement = options.replacement ?? '💡 NOTE';
visit(tree, 'text', (node) => {
if (node.value.includes(marker)) {
node.value = node.value.replaceAll(marker, replacement);
}
});
};
Exposing it from your plugin entry
// src/index.ts
export { default } from './plugin';
export { createStarterRemarkPlugin } from './remark/starterRemarkPlugin';
How users consume it
import pluginStarter from 'docusaurus-plugin-starter';
export default {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
remarkPlugins: [
pluginStarter.createStarterRemarkPlugin({
marker: 'NOTE',
replacement: '💡 NOTE',
}),
],
},
},
],
],
};
AST traversal tips
- Use
unist-util-visitrather than recursing by hand - Skip
code/inlineCode/linknodes if you don't want to transform inside them - For injecting MDXMDX A Markdown-based format that lets you write JSX inside your markdown, used by Docusaurus v3 for docs and pages. JSX (like the glossary plugin does), you'll need to add an
importvia anmdxjsEsmnode plus producemdxJsxTextElementnodes - If your transform needs async work (file reads, API calls), make the transformer async and return the tree explicitly