or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

build-dev.mdcli.mdclient-api.mdconfiguration.mdindex.mdmarkdown.mdtheming.md

markdown.mddocs/

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

```