Astro's internal markdown processing library that provides a unified markdown processor built on remark and rehype ecosystem plugins with syntax highlighting, frontmatter parsing, and image processing capabilities.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
Built-in rehype plugins for heading processing, image optimization, and syntax highlighting integration within the HTML processing pipeline.
Adds id attributes to headings based on their text content and collects heading metadata.
/**
* Rehype plugin that adds id attributes to headings and collects metadata
* @param options - Optional configuration object
* @returns Rehype plugin function
*/
function rehypeHeadingIds(options?: {
/** Enable experimental heading ID compatibility mode */
experimentalHeadingIdCompat?: boolean;
}): ReturnType<RehypePlugin>;Usage Examples:
import { createMarkdownProcessor, rehypeHeadingIds } from "@astrojs/markdown-remark";
// Using as part of processor configuration
const processor = await createMarkdownProcessor({
rehypePlugins: [
[rehypeHeadingIds, { experimentalHeadingIdCompat: false }]
]
});
const result = await processor.render(`
# Main Title
## Section One
### Subsection
## Another Section
`);
console.log(result.metadata.headings);
// [
// { depth: 1, slug: "main-title", text: "Main Title" },
// { depth: 2, slug: "section-one", text: "Section One" },
// { depth: 3, slug: "subsection", text: "Subsection" },
// { depth: 2, slug: "another-section", text: "Another Section" }
// ]
// Generated HTML will have id attributes:
// <h1 id="main-title">Main Title</h1>
// <h2 id="section-one">Section One</h2>
// <h3 id="subsection">Subsection</h3>
// <h2 id="another-section">Another Section</h2>Features:
Rehype plugin that integrates Shiki syntax highlighting into the HTML processing pipeline.
/**
* Shiki syntax highlighting rehype plugin
* @param config - Shiki configuration options
* @param excludeLangs - Optional array of languages to exclude
* @returns Rehype plugin function
*/
const rehypeShiki: Plugin<[ShikiConfig, string[]?], Root>;Usage Examples:
import { createMarkdownProcessor, rehypeShiki } from "@astrojs/markdown-remark";
// Using in processor configuration
const processor = await createMarkdownProcessor({
rehypePlugins: [
[rehypeShiki, {
theme: 'github-dark',
themes: {
light: 'github-light',
dark: 'github-dark'
},
wrap: true,
transformers: [],
langAlias: {
'js': 'javascript',
'ts': 'typescript'
}
}, ['math', 'mermaid']] // Exclude languages
]
});
// Markdown with code blocks
const result = await processor.render(`
\`\`\`javascript
console.log("Hello, world!");
\`\`\`
\`\`\`python
print("Hello from Python!")
\`\`\`
\`\`\`math
E = mc^2
\`\`\`
`);
// JavaScript and Python blocks will be highlighted
// Math block will be excluded from highlightingRehype plugin that integrates Prism syntax highlighting into the HTML processing pipeline.
/**
* Prism syntax highlighting rehype plugin
* @param excludeLangs - Optional array of languages to exclude
* @returns Rehype plugin function
*/
const rehypePrism: Plugin<[string[]?], Root>;Usage Examples:
import { createMarkdownProcessor, rehypePrism } from "@astrojs/markdown-remark";
// Using in processor configuration
const processor = await createMarkdownProcessor({
syntaxHighlight: { type: 'prism' },
rehypePlugins: [
[rehypePrism, ['math', 'mermaid']] // Exclude languages
]
});
const result = await processor.render(`
\`\`\`javascript
function greet(name) {
return \`Hello, \${name}!\`;
}
\`\`\`
`);
// Code block will be highlighted using Prism
// Output includes Prism CSS classes and is:raw directiveProcesses images for Astro's image optimization system by adding special properties and metadata.
/**
* Process images for Astro's image optimization
* @returns Rehype plugin function
*/
function rehypeImages(): Plugin<[], Root>;Usage Examples:
import { createMarkdownProcessor, rehypeImages } from "@astrojs/markdown-remark";
// Using in processor configuration (usually automatic)
const processor = await createMarkdownProcessor({
rehypePlugins: [rehypeImages],
image: {
domains: ['example.com'],
remotePatterns: [
{
protocol: 'https',
hostname: '**.githubusercontent.com'
}
]
}
});
const result = await processor.render(`



`);
console.log(result.metadata.localImagePaths); // ['./assets/image.png']
console.log(result.metadata.remoteImagePaths); // ['https://example.com/image.jpg']
// Images are processed with special __ASTRO_IMAGE__ properties
// Local and allowed remote images get optimization metadata
// Disallowed remote images are left unchangedFeatures:
These plugins are automatically integrated into the default markdown processing pipeline:
// Default plugin order in createMarkdownProcessor:
// 1. Remark plugins (user + built-in)
// 2. remarkCollectImages (for image metadata)
// 3. remark-rehype (convert to HTML AST)
// 4. rehypeShiki or rehypePrism (syntax highlighting)
// 5. User rehype plugins
// 6. rehypeImages (image processing)
// 7. rehypeHeadingIds (heading processing)
// 8. rehype-raw + rehype-stringify (HTML output)You can also use these plugins manually with unified:
import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';
import { rehypeHeadingIds, rehypeImages } from '@astrojs/markdown-remark';
const processor = unified()
.use(remarkParse)
.use(remarkRehype)
.use(rehypeHeadingIds)
.use(rehypeImages)
.use(rehypeStringify);
const result = await processor.process('# Hello World');Each plugin can be configured when used in the rehypePlugins array:
const processor = await createMarkdownProcessor({
rehypePlugins: [
// Plugin without options
rehypeImages,
// Plugin with options
[rehypeHeadingIds, {
experimentalHeadingIdCompat: true
}],
// Plugin with multiple parameters
[rehypeShiki, {
theme: 'github-dark',
wrap: true
}, ['math']]
]
});The plugins handle various edge cases:
All plugins are designed to be fault-tolerant and will not break the processing pipeline if they encounter unexpected input.