0
# Markdown Processing API
1
2
VitePress provides an enhanced markdown processing system built on MarkdownIt with Vue component support, syntax highlighting, custom containers, and extensive plugin ecosystem. The markdown processor supports frontmatter, custom renderers, and seamless integration with Vue components.
3
4
## Capabilities
5
6
### Markdown Renderer Creation
7
8
Core functions for creating and configuring markdown renderers with VitePress enhancements.
9
10
#### createMarkdownRenderer
11
12
Creates a fully configured MarkdownIt instance with VitePress plugins and enhancements.
13
14
```typescript { .api }
15
/**
16
* Creates markdown renderer instance with VitePress plugins
17
* @param options - Markdown processing configuration
18
* @param base - Base URL for resolving relative links
19
* @param logger - Logger instance for debugging
20
* @returns Configured MarkdownIt instance with VitePress plugins
21
*/
22
function createMarkdownRenderer(
23
options?: MarkdownOptions,
24
base?: string,
25
logger?: Logger
26
): MarkdownIt;
27
28
interface MarkdownOptions {
29
/**
30
* Show line numbers in code blocks
31
* @default false
32
*/
33
lineNumbers?: boolean;
34
35
/**
36
* Custom MarkdownIt configuration function
37
*/
38
config?: (md: MarkdownIt) => void;
39
40
/**
41
* Pre-configuration hook (runs before VitePress plugins)
42
*/
43
preConfig?: (md: MarkdownIt) => void;
44
45
/**
46
* Enable/disable markdown caching
47
* @default true
48
*/
49
cache?: boolean;
50
51
/**
52
* Syntax highlighting theme configuration
53
*/
54
theme?: ThemeOptions | { light: ThemeOptions; dark: ThemeOptions };
55
56
/**
57
* Supported programming languages for syntax highlighting
58
*/
59
languages?: LanguageInput[];
60
61
/**
62
* Custom transformers for syntax highlighting
63
*/
64
transformers?: ShikiTransformer[];
65
66
/**
67
* Default language for code blocks without specified language
68
*/
69
defaultHighlightLang?: string;
70
71
/**
72
* Code groups configuration
73
*/
74
codeTransformers?: CodeTransformer[];
75
76
/**
77
* Anchor links configuration
78
*/
79
anchor?: AnchorOptions;
80
81
/**
82
* Table of contents generation options
83
*/
84
toc?: TocOptions;
85
86
/**
87
* External links attributes and processing
88
*/
89
externalLinks?: Record<string, string>;
90
91
/**
92
* Math rendering configuration
93
*/
94
math?: boolean | MathOptions;
95
96
/**
97
* Image processing options
98
*/
99
image?: ImageOptions;
100
101
/**
102
* Custom container configuration
103
*/
104
container?: ContainerOptions;
105
106
/**
107
* Markdown parser options (passed to MarkdownIt)
108
*/
109
breaks?: boolean;
110
linkify?: boolean;
111
typographer?: boolean;
112
quotes?: string | string[];
113
}
114
```
115
116
**Usage Examples:**
117
118
```typescript
119
import { createMarkdownRenderer } from "vitepress";
120
121
// Basic markdown renderer
122
const md = createMarkdownRenderer();
123
const html = md.render("# Hello World\n\nThis is **bold** text.");
124
125
// Custom renderer with syntax highlighting
126
const md = createMarkdownRenderer({
127
lineNumbers: true,
128
theme: {
129
light: "github-light",
130
dark: "github-dark"
131
},
132
languages: ["javascript", "typescript", "vue", "bash"],
133
defaultHighlightLang: "text"
134
});
135
136
// Advanced configuration with custom plugins
137
const md = createMarkdownRenderer({
138
config: (md) => {
139
// Add custom MarkdownIt plugins
140
md.use(require("markdown-it-footnote"));
141
md.use(require("markdown-it-deflist"));
142
143
// Custom renderer rules
144
md.renderer.rules.table_open = () => '<div class="table-container"><table>';
145
md.renderer.rules.table_close = () => '</table></div>';
146
},
147
148
preConfig: (md) => {
149
// Pre-configuration (runs before VitePress plugins)
150
md.set({ breaks: true, linkify: true });
151
},
152
153
externalLinks: {
154
target: "_blank",
155
rel: "noopener noreferrer"
156
}
157
});
158
159
// Math and advanced features
160
const md = createMarkdownRenderer({
161
math: true,
162
anchor: {
163
permalink: true,
164
permalinkBefore: true,
165
permalinkSymbol: "#"
166
},
167
container: {
168
tipLabel: "TIP",
169
warningLabel: "WARNING",
170
dangerLabel: "DANGER",
171
infoLabel: "INFO"
172
}
173
});
174
```
175
176
### Configuration Interfaces
177
178
Detailed configuration options for markdown processing features.
179
180
#### Syntax Highlighting Options
181
182
```typescript { .api }
183
interface ThemeOptions {
184
/**
185
* Shiki theme name or theme object
186
*/
187
name?: string;
188
189
/**
190
* Custom theme definition
191
*/
192
theme?: Theme;
193
}
194
195
type LanguageInput =
196
| string
197
| {
198
id: string;
199
scopeName: string;
200
grammar: Grammar;
201
aliases?: string[];
202
};
203
204
interface CodeTransformer {
205
/**
206
* Transform code blocks
207
*/
208
name: string;
209
preprocess?: (code: string, options: any) => string;
210
postprocess?: (html: string, options: any) => string;
211
}
212
213
interface ShikiTransformer {
214
name: string;
215
preprocess?: (code: string, options: TransformerOptions) => string;
216
postprocess?: (html: string, options: TransformerOptions) => string;
217
tokens?: (tokens: ThemedToken[][], options: TransformerOptions) => void;
218
}
219
```
220
221
#### Anchor and Navigation Options
222
223
```typescript { .api }
224
interface AnchorOptions {
225
/**
226
* Minimum header level to generate anchors for
227
* @default 2
228
*/
229
level?: [number, number];
230
231
/**
232
* Generate permalink anchors
233
* @default true
234
*/
235
permalink?: boolean;
236
237
/**
238
* Permalink symbol
239
* @default '#'
240
*/
241
permalinkSymbol?: string;
242
243
/**
244
* Place permalink before header text
245
* @default false
246
*/
247
permalinkBefore?: boolean;
248
249
/**
250
* Custom permalink render function
251
*/
252
permalinkHref?: (slug: string) => string;
253
254
/**
255
* Custom slug generation function
256
*/
257
slugify?: (str: string) => string;
258
259
/**
260
* Additional CSS classes for anchor links
261
*/
262
permalinkClass?: string;
263
264
/**
265
* ARIA label for anchor links
266
*/
267
permalinkAriaLabel?: string;
268
}
269
270
interface TocOptions {
271
/**
272
* Header levels to include in TOC
273
* @default [2, 3]
274
*/
275
level?: [number, number];
276
277
/**
278
* Custom slug function for TOC links
279
*/
280
slugify?: (str: string) => string;
281
282
/**
283
* Include anchor links in TOC
284
* @default true
285
*/
286
includeLevel?: number[];
287
288
/**
289
* Custom TOC marker token
290
*/
291
markerPattern?: RegExp;
292
}
293
```
294
295
#### Container and Extensions Options
296
297
```typescript { .api }
298
interface ContainerOptions {
299
/**
300
* Custom container labels
301
*/
302
tipLabel?: string;
303
warningLabel?: string;
304
dangerLabel?: string;
305
infoLabel?: string;
306
detailsLabel?: string;
307
308
/**
309
* Custom container types
310
*/
311
customTypes?: Record<string, ContainerType>;
312
}
313
314
interface ContainerType {
315
/**
316
* Container label/title
317
*/
318
label?: string;
319
320
/**
321
* Custom render function
322
*/
323
render?: (tokens: Token[], idx: number, options: any, env: any) => string;
324
325
/**
326
* Container CSS class
327
*/
328
className?: string;
329
}
330
331
interface MathOptions {
332
/**
333
* Math rendering engine
334
* @default 'mathjax'
335
*/
336
engine?: "mathjax" | "katex";
337
338
/**
339
* Math delimiters configuration
340
*/
341
delimiters?: {
342
inline?: [string, string];
343
block?: [string, string];
344
};
345
346
/**
347
* Engine-specific options
348
*/
349
options?: Record<string, any>;
350
}
351
352
interface ImageOptions {
353
/**
354
* Enable lazy loading for images
355
* @default false
356
*/
357
lazy?: boolean;
358
359
/**
360
* Generate responsive image sets
361
* @default false
362
*/
363
responsive?: boolean;
364
365
/**
366
* Image optimization options
367
*/
368
optimization?: {
369
/**
370
* Enable WebP conversion
371
*/
372
webp?: boolean;
373
374
/**
375
* Quality settings
376
*/
377
quality?: number;
378
379
/**
380
* Resize breakpoints
381
*/
382
breakpoints?: number[];
383
};
384
}
385
```
386
387
### Markdown Environment and Context
388
389
Environment and context objects used during markdown processing.
390
391
#### MarkdownEnv
392
393
Environment object passed through the markdown rendering pipeline.
394
395
```typescript { .api }
396
/**
397
* Markdown rendering environment containing metadata and context
398
*/
399
interface MarkdownEnv {
400
/**
401
* Raw markdown content without frontmatter
402
*/
403
content?: string;
404
405
/**
406
* Extracted excerpt (rendered or raw based on configuration)
407
*/
408
excerpt?: string;
409
410
/**
411
* Parsed frontmatter data
412
*/
413
frontmatter?: Record<string, unknown>;
414
415
/**
416
* Extracted headers from content
417
*/
418
headers?: Header[];
419
420
/**
421
* Vue SFC blocks extracted from markdown
422
*/
423
sfcBlocks?: MarkdownSfcBlocks;
424
425
/**
426
* Extracted page title
427
*/
428
title?: string;
429
430
/**
431
* Current file path being processed
432
*/
433
path: string;
434
435
/**
436
* Relative path from source root
437
*/
438
relativePath: string;
439
440
/**
441
* Whether clean URLs are enabled
442
*/
443
cleanUrls: boolean;
444
445
/**
446
* Links found in the content
447
*/
448
links?: string[];
449
450
/**
451
* Included file references
452
*/
453
includes?: string[];
454
455
/**
456
* Real file system path (may differ from path for virtual files)
457
*/
458
realPath?: string;
459
460
/**
461
* Current locale index for multi-language sites
462
*/
463
localeIndex?: string;
464
}
465
```
466
467
#### SFC Blocks
468
469
Vue Single File Component blocks extracted from markdown.
470
471
```typescript { .api }
472
interface MarkdownSfcBlocks {
473
/**
474
* Main template block
475
*/
476
template: SfcBlock | null;
477
478
/**
479
* Main script block
480
*/
481
script: SfcBlock | null;
482
483
/**
484
* Script setup block
485
*/
486
scriptSetup: SfcBlock | null;
487
488
/**
489
* All script blocks (including custom types)
490
*/
491
scripts: SfcBlock[];
492
493
/**
494
* All style blocks
495
*/
496
styles: SfcBlock[];
497
498
/**
499
* Custom blocks (e.g., i18n, docs)
500
*/
501
customBlocks: SfcBlock[];
502
}
503
504
interface SfcBlock {
505
/**
506
* Block type (script, style, template, etc.)
507
*/
508
type: string;
509
510
/**
511
* Full block content including tags
512
*/
513
content: string;
514
515
/**
516
* Content with opening and closing tags stripped
517
*/
518
contentStripped: string;
519
520
/**
521
* Opening tag
522
*/
523
tagOpen: string;
524
525
/**
526
* Closing tag
527
*/
528
tagClose: string;
529
}
530
```
531
532
### Content Loading and Processing
533
534
Advanced content loading and processing capabilities.
535
536
#### createContentLoader
537
538
Create content loaders for processing multiple markdown files with shared processing logic.
539
540
```typescript { .api }
541
/**
542
* Creates a content loader for markdown files
543
* @param pattern - Glob patterns for files to load
544
* @param options - Loader configuration options
545
* @returns Object with watch and load properties for content loading
546
*/
547
function createContentLoader<T = ContentData[]>(
548
pattern: string | string[],
549
options?: ContentOptions<T>
550
): ContentLoader<T>;
551
552
interface ContentOptions<T> {
553
/**
554
* Include raw source content
555
* @default false
556
*/
557
includeSrc?: boolean;
558
559
/**
560
* Render markdown to HTML
561
* @default false
562
*/
563
render?: boolean;
564
565
/**
566
* Extract excerpt from content
567
*/
568
excerpt?: boolean | string | ((file: ContentData, options: ContentOptions<T>) => string);
569
570
/**
571
* Transform loaded data
572
*/
573
transform?: (data: ContentData[], options: ContentOptions<T>) => T | Promise<T>;
574
575
/**
576
* Glob options for file matching
577
*/
578
globOptions?: GlobOptions;
579
}
580
581
interface ContentData {
582
/**
583
* Content URL/path
584
*/
585
url: string;
586
587
/**
588
* Raw markdown source (if includeSrc: true)
589
*/
590
src?: string;
591
592
/**
593
* Rendered HTML (if render: true)
594
*/
595
html?: string;
596
597
/**
598
* Frontmatter data
599
*/
600
frontmatter: Record<string, any>;
601
602
/**
603
* Extracted excerpt (if excerpt option enabled)
604
*/
605
excerpt?: string;
606
}
607
608
interface ContentLoader<T> {
609
/**
610
* Files to watch for changes
611
*/
612
watch: string[];
613
614
/**
615
* Load and process content
616
*/
617
load(): Promise<T>;
618
}
619
```
620
621
**Usage Examples:**
622
623
```typescript
624
// Basic content loading
625
const loader = createContentLoader("posts/*.md", {
626
includeSrc: true,
627
render: true,
628
excerpt: true
629
});
630
631
const posts = await loader.load();
632
633
// Advanced content processing with transformation
634
const blogLoader = createContentLoader("blog/**/*.md", {
635
render: true,
636
excerpt: "<!-- more -->",
637
transform: (data) => {
638
return data
639
.filter(post => post.frontmatter.published !== false)
640
.sort((a, b) => +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date))
641
.map(post => ({
642
...post,
643
readingTime: calculateReadingTime(post.src)
644
}));
645
}
646
});
647
648
// Use in data files (.data.ts)
649
export default {
650
watch: ["./posts/**/*.md"],
651
load: () => blogLoader.load()
652
};
653
```
654
655
#### defineLoader
656
657
Type helper for defining data loaders with proper TypeScript support.
658
659
```typescript { .api }
660
/**
661
* Type helper for defining data loaders
662
* @param loader - LoaderModule object with watch and load properties
663
* @returns Same loader object for type inference
664
*/
665
function defineLoader<T = any>(loader: LoaderModule<T>): LoaderModule<T>;
666
667
interface LoaderModule<T = any> {
668
/**
669
* Files or patterns to watch for changes
670
*/
671
watch?: string[] | string;
672
673
/**
674
* Load function that returns data
675
* @param watchedFiles - Array of watched file paths that changed
676
* @returns Data to be used in pages
677
*/
678
load: (watchedFiles: string[]) => T | Promise<T>;
679
}
680
```
681
682
**Usage Examples:**
683
684
```typescript
685
// blog-posts.data.ts
686
import { defineLoader } from "vitepress";
687
import { createContentLoader } from "vitepress";
688
689
export default defineLoader({
690
watch: ["./blog/**/*.md"],
691
load: async (watchedFiles) => {
692
const loader = createContentLoader("blog/**/*.md", {
693
render: true,
694
excerpt: true,
695
transform: (data) => data
696
.filter(post => post.frontmatter.published)
697
.sort((a, b) => +new Date(b.frontmatter.date) - +new Date(a.frontmatter.date))
698
});
699
700
return await loader.load();
701
}
702
});
703
704
// Use loaded data in pages
705
<script setup>
706
import { data as posts } from "./blog-posts.data";
707
708
// posts is typed and contains processed blog data
709
console.log("Latest posts:", posts.slice(0, 5));
710
</script>
711
```
712
713
### Custom Markdown Plugins
714
715
Creating and configuring custom markdown plugins for extended functionality.
716
717
#### Plugin Development
718
719
```typescript { .api }
720
/**
721
* Custom MarkdownIt plugin function signature
722
*/
723
type MarkdownItPlugin = (
724
md: MarkdownIt,
725
options?: any
726
) => void;
727
728
/**
729
* VitePress markdown plugin with additional context
730
*/
731
interface VitePressPlugin {
732
/**
733
* Plugin name for debugging
734
*/
735
name: string;
736
737
/**
738
* Plugin configuration function
739
*/
740
configureParser?: (md: MarkdownIt, options: MarkdownOptions) => void;
741
742
/**
743
* Plugin render function
744
*/
745
configureRenderer?: (md: MarkdownIt, env: MarkdownEnv) => void;
746
747
/**
748
* Plugin cleanup function
749
*/
750
cleanup?: () => void;
751
}
752
```
753
754
**Usage Examples:**
755
756
```typescript
757
// Custom plugin for special containers
758
const customContainerPlugin: MarkdownItPlugin = (md, options) => {
759
const containerPlugin = require("markdown-it-container");
760
761
// Add custom "demo" container
762
md.use(containerPlugin, "demo", {
763
render: (tokens, idx, _options, env) => {
764
const token = tokens[idx];
765
const info = token.info.trim().slice(4).trim(); // Remove "demo"
766
767
if (token.nesting === 1) {
768
// Opening tag
769
return `<div class="demo-container">
770
<div class="demo-title">${info || "Demo"}</div>
771
<div class="demo-content">`;
772
} else {
773
// Closing tag
774
return `</div></div>`;
775
}
776
}
777
});
778
};
779
780
// Use in VitePress config
781
export default defineConfig({
782
markdown: {
783
config: (md) => {
784
md.use(customContainerPlugin);
785
786
// Add custom renderer for code blocks
787
const fence = md.renderer.rules.fence!;
788
md.renderer.rules.fence = (...args) => {
789
const [tokens, idx] = args;
790
const token = tokens[idx];
791
const lang = token.info.trim();
792
793
// Add copy button to code blocks
794
const result = fence(...args);
795
return result.replace(
796
/<\/div>$/,
797
`<button class="copy-code">Copy</button></div>`
798
);
799
};
800
}
801
}
802
});
803
```