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

client-api.mddocs/

0

# Client-Side API

1

2

VitePress client-side API provides composables and utilities for accessing runtime data, navigation, and page information. Essential for building custom themes and Vue components in markdown files.

3

4

## Capabilities

5

6

### Core Composables

7

8

Vue composables for accessing VitePress runtime state and functionality.

9

10

#### useData

11

12

Access VitePress runtime data including site configuration, page data, and theme configuration.

13

14

```typescript { .api }

15

/**

16

* Access VitePress runtime data

17

* @returns VitePressData object containing reactive site and page data

18

*/

19

function useData<T = any>(): VitePressData<T>;

20

21

interface VitePressData<T> {

22

/**

23

* Reactive site-level data and configuration

24

*/

25

site: Ref<SiteData<T>>;

26

27

/**

28

* Reactive theme configuration

29

*/

30

theme: Ref<T>;

31

32

/**

33

* Reactive current page data

34

*/

35

page: Ref<PageData>;

36

37

/**

38

* Reactive frontmatter of current page

39

*/

40

frontmatter: Ref<Record<string, any>>;

41

42

/**

43

* Reactive route parameters for dynamic routes

44

*/

45

params: Ref<Record<string, string>>;

46

47

/**

48

* Computed page title (from frontmatter or page data)

49

*/

50

title: Ref<string>;

51

52

/**

53

* Computed page description (from frontmatter or page data)

54

*/

55

description: Ref<string>;

56

57

/**

58

* Current language code

59

*/

60

lang: Ref<string>;

61

62

/**

63

* Text direction (ltr/rtl)

64

*/

65

dir: Ref<string>;

66

67

/**

68

* Current locale index for multi-language sites

69

*/

70

localeIndex: Ref<string>;

71

72

/**

73

* Dark mode state (reactive)

74

*/

75

isDark: Ref<boolean>;

76

}

77

```

78

79

**Usage Examples:**

80

81

```vue

82

<script setup>

83

import { useData } from "vitepress";

84

85

const { site, page, theme, frontmatter, isDark } = useData();

86

87

// Access site information

88

console.log("Site title:", site.value.title);

89

console.log("Base URL:", site.value.base);

90

91

// Access page information

92

console.log("Page title:", page.value.title);

93

console.log("Page path:", page.value.relativePath);

94

95

// Access theme configuration

96

console.log("Nav items:", theme.value.nav);

97

98

// Access frontmatter

99

console.log("Page tags:", frontmatter.value.tags);

100

101

// React to dark mode changes

102

watch(isDark, (dark) => {

103

console.log("Dark mode:", dark ? "enabled" : "disabled");

104

});

105

</script>

106

107

<template>

108

<div :class="{ dark: isDark }">

109

<h1>{{ page.title }}</h1>

110

<p>{{ page.description }}</p>

111

<div v-if="frontmatter.tags">

112

<span v-for="tag in frontmatter.tags" :key="tag" class="tag">

113

{{ tag }}

114

</span>

115

</div>

116

</div>

117

</template>

118

```

119

120

#### useRouter

121

122

Access VitePress router for programmatic navigation and route handling.

123

124

```typescript { .api }

125

/**

126

* Access VitePress router instance

127

* @returns Router object with navigation methods and hooks

128

*/

129

function useRouter(): Router;

130

131

interface Router {

132

/**

133

* Current route information

134

*/

135

route: Route;

136

137

/**

138

* Navigate to a new URL

139

* @param to - Target URL or path

140

* @returns Promise that resolves after navigation

141

*/

142

go(to?: string): Promise<void>;

143

144

/**

145

* Hook called before route changes

146

*/

147

onBeforeRouteChange?: (to: string) => Awaitable<void | boolean>;

148

149

/**

150

* Hook called before page loads

151

*/

152

onBeforePageLoad?: (to: string) => Awaitable<void | boolean>;

153

154

/**

155

* Hook called after page loads

156

*/

157

onAfterPageLoad?: (to: string) => Awaitable<void>;

158

159

/**

160

* Hook called after route changes

161

*/

162

onAfterRouteChange?: (to: string) => Awaitable<void>;

163

}

164

```

165

166

**Usage Examples:**

167

168

```vue

169

<script setup>

170

import { useRouter, onMounted } from "vitepress";

171

172

const router = useRouter();

173

174

// Navigate programmatically

175

const goToPage = (path) => {

176

router.go(path);

177

};

178

179

// Set up navigation hooks

180

onMounted(() => {

181

router.onBeforeRouteChange = async (to) => {

182

console.log("Navigating to:", to);

183

// Return false to cancel navigation

184

if (to.includes("restricted")) {

185

return false;

186

}

187

};

188

189

router.onAfterPageLoad = async (to) => {

190

console.log("Page loaded:", to);

191

// Update analytics, scroll position, etc.

192

trackPageView(to);

193

};

194

});

195

196

const trackPageView = (path) => {

197

// Analytics tracking logic

198

};

199

</script>

200

201

<template>

202

<nav>

203

<button @click="goToPage('/guide/')">Guide</button>

204

<button @click="goToPage('/api/')">API</button>

205

<button @click="goToPage('/examples/')">Examples</button>

206

</nav>

207

</template>

208

```

209

210

#### useRoute

211

212

Access current route information and reactive route state.

213

214

```typescript { .api }

215

/**

216

* Access current route information

217

* @returns Current Route object with path, data, and component

218

*/

219

function useRoute(): Route;

220

221

interface Route {

222

/**

223

* Current path

224

*/

225

path: string;

226

227

/**

228

* Current page data

229

*/

230

data: PageData;

231

232

/**

233

* Current page component

234

*/

235

component: Component | null;

236

}

237

```

238

239

**Usage Examples:**

240

241

```vue

242

<script setup>

243

import { useRoute, computed } from "vitepress";

244

245

const route = useRoute();

246

247

// Reactive computed properties based on route

248

const isHomePage = computed(() => route.path === "/");

249

const isApiPage = computed(() => route.path.startsWith("/api/"));

250

const currentSection = computed(() => {

251

const segments = route.path.split("/").filter(Boolean);

252

return segments[0] || "home";

253

});

254

255

// Access route data

256

console.log("Current path:", route.path);

257

console.log("Page headers:", route.data.headers);

258

</script>

259

260

<template>

261

<div>

262

<div v-if="isHomePage" class="home-banner">

263

Welcome to the homepage!

264

</div>

265

266

<nav class="breadcrumb">

267

<span class="section" :class="{ active: currentSection === 'home' }">

268

Home

269

</span>

270

<span v-if="!isHomePage" class="section active">

271

{{ currentSection }}

272

</span>

273

</nav>

274

275

<div v-if="isApiPage" class="api-notice">

276

You're viewing API documentation

277

</div>

278

</div>

279

</template>

280

```

281

282

### Client Utilities

283

284

Utility functions for common client-side operations and URL handling.

285

286

#### withBase

287

288

Prepend configured base URL to internal links and paths.

289

290

```typescript { .api }

291

/**

292

* Prepend configured base to internal URLs

293

* @param path - URL path string

294

* @returns URL with base prepended

295

*/

296

function withBase(path: string): string;

297

```

298

299

**Usage Examples:**

300

301

```vue

302

<script setup>

303

import { withBase, useData } from "vitepress";

304

305

const { site } = useData();

306

307

// Ensure links work with custom base URLs

308

const logoUrl = withBase("/logo.svg");

309

const apiUrl = withBase("/api/reference");

310

311

// Dynamic asset paths

312

const getAssetUrl = (filename) => withBase(`/assets/${filename}`);

313

</script>

314

315

<template>

316

<header>

317

<img :src="logoUrl" :alt="site.title" />

318

<nav>

319

<a :href="withBase('/guide/')">Guide</a>

320

<a :href="apiUrl">API Reference</a>

321

</nav>

322

</header>

323

324

<main>

325

<img :src="getAssetUrl('hero-image.jpg')" alt="Hero" />

326

</main>

327

</template>

328

```

329

330

#### onContentUpdated

331

332

Register callbacks for content updates and page changes.

333

334

```typescript { .api }

335

/**

336

* Register callback for content updates

337

* @param fn - Callback function to execute on content updates

338

* @returns void (auto-unregisters on component unmount)

339

*/

340

function onContentUpdated(fn: () => any): void;

341

```

342

343

**Usage Examples:**

344

345

```vue

346

<script setup>

347

import { onContentUpdated, nextTick } from "vitepress";

348

349

// Update third-party widgets when content changes

350

onContentUpdated(() => {

351

// Reinitialize syntax highlighters

352

if (window.Prism) {

353

window.Prism.highlightAll();

354

}

355

356

// Update table of contents

357

updateTableOfContents();

358

359

// Scroll to hash if present

360

nextTick(() => {

361

const hash = window.location.hash;

362

if (hash) {

363

const element = document.querySelector(hash);

364

element?.scrollIntoView();

365

}

366

});

367

});

368

369

const updateTableOfContents = () => {

370

// Custom TOC update logic

371

const headers = document.querySelectorAll("h1, h2, h3, h4, h5, h6");

372

console.log("Found headers:", headers.length);

373

};

374

</script>

375

```

376

377

#### defineClientComponent

378

379

Define async components for client-side rendering with SSR compatibility.

380

381

```typescript { .api }

382

/**

383

* Define async component for client-side rendering

384

* @param loader - AsyncComponentLoader function

385

* @param args - Component arguments

386

* @param cb - Completion callback

387

* @returns Component definition object with SSR support

388

*/

389

function defineClientComponent(

390

loader: AsyncComponentLoader,

391

args?: any,

392

cb?: () => void

393

): Component;

394

395

type AsyncComponentLoader = () => Promise<Component>;

396

```

397

398

**Usage Examples:**

399

400

```vue

401

<script setup>

402

import { defineClientComponent } from "vitepress";

403

404

// Define client-only component (e.g., interactive widgets)

405

const InteractiveChart = defineClientComponent(

406

() => import("./components/InteractiveChart.vue"),

407

{

408

// Component props

409

data: chartData,

410

options: chartOptions

411

},

412

() => {

413

console.log("Chart component loaded");

414

}

415

);

416

417

// Define component with loading state

418

const HeavyWidget = defineClientComponent(

419

() => import("./components/HeavyWidget.vue"),

420

{},

421

() => {

422

// Initialize widget after loading

423

initializeWidget();

424

}

425

);

426

</script>

427

428

<template>

429

<div>

430

<h2>Data Visualization</h2>

431

<InteractiveChart v-if="chartData" />

432

<div v-else>Loading chart...</div>

433

434

<h2>Advanced Features</h2>

435

<HeavyWidget />

436

</div>

437

</template>

438

```

439

440

#### getScrollOffset

441

442

Calculate scroll offset based on site configuration for proper anchor positioning.

443

444

```typescript { .api }

445

/**

446

* Calculate scroll offset based on site configuration

447

* @returns Scroll offset in pixels

448

*/

449

function getScrollOffset(): number;

450

```

451

452

**Usage Examples:**

453

454

```vue

455

<script setup>

456

import { getScrollOffset } from "vitepress";

457

458

// Custom scroll behavior

459

const scrollToElement = (elementId) => {

460

const element = document.getElementById(elementId);

461

if (element) {

462

const offset = getScrollOffset();

463

const top = element.offsetTop - offset;

464

465

window.scrollTo({

466

top,

467

behavior: "smooth"

468

});

469

}

470

};

471

472

// Handle anchor clicks with proper offset

473

const handleAnchorClick = (event, hash) => {

474

event.preventDefault();

475

scrollToElement(hash.slice(1));

476

477

// Update URL without jumping

478

history.pushState(null, null, hash);

479

};

480

</script>

481

482

<template>

483

<nav class="table-of-contents">

484

<ul>

485

<li v-for="header in headers" :key="header.slug">

486

<a

487

:href="`#${header.slug}`"

488

@click="handleAnchorClick($event, `#${header.slug}`)"

489

>

490

{{ header.title }}

491

</a>

492

</li>

493

</ul>

494

</nav>

495

</template>

496

```

497

498

### Environment Detection

499

500

Constants and utilities for detecting the runtime environment.

501

502

#### inBrowser

503

504

Boolean constant indicating whether code is running in browser environment.

505

506

```typescript { .api }

507

/**

508

* Whether code is running in browser environment

509

*/

510

const inBrowser: boolean;

511

```

512

513

**Usage Examples:**

514

515

```vue

516

<script setup>

517

import { inBrowser } from "vitepress";

518

519

// Conditionally run browser-only code

520

if (inBrowser) {

521

// Safe to access window, document, localStorage, etc.

522

console.log("Running in browser");

523

console.log("User agent:", navigator.userAgent);

524

525

// Initialize browser-only features

526

initializeAnalytics();

527

setupKeyboardShortcuts();

528

} else {

529

console.log("Running on server (SSR)");

530

}

531

532

const initializeAnalytics = () => {

533

// Browser-only analytics code

534

if (typeof window !== "undefined" && window.gtag) {

535

window.gtag("config", "GA_MEASUREMENT_ID");

536

}

537

};

538

539

const setupKeyboardShortcuts = () => {

540

if (inBrowser) {

541

document.addEventListener("keydown", (event) => {

542

if (event.ctrlKey && event.key === "k") {

543

// Open search

544

openSearch();

545

}

546

});

547

}

548

};

549

</script>

550

```

551

552

### Content Component

553

554

Vue component for rendering markdown content within Vue templates.

555

556

#### Content

557

558

Component for rendering processed markdown content with Vue component support.

559

560

```typescript { .api }

561

/**

562

* Component for rendering markdown content

563

*/

564

const Content: Component;

565

```

566

567

**Usage Examples:**

568

569

```vue

570

<script setup>

571

import { Content, useData } from "vitepress";

572

573

const { page, frontmatter } = useData();

574

575

// Custom content wrapper with additional features

576

const showTableOfContents = computed(() =>

577

frontmatter.value.toc !== false && page.value.headers.length > 1

578

);

579

</script>

580

581

<template>

582

<div class="content-wrapper">

583

<header v-if="frontmatter.showHeader !== false">

584

<h1>{{ page.title }}</h1>

585

<p class="description">{{ page.description }}</p>

586

587

<div v-if="frontmatter.tags" class="tags">

588

<span v-for="tag in frontmatter.tags" :key="tag" class="tag">

589

{{ tag }}

590

</span>

591

</div>

592

</header>

593

594

<aside v-if="showTableOfContents" class="table-of-contents">

595

<h2>On This Page</h2>

596

<nav>

597

<ul>

598

<li v-for="header in page.headers" :key="header.slug">

599

<a :href="`#${header.slug}`">{{ header.title }}</a>

600

</li>

601

</ul>

602

</nav>

603

</aside>

604

605

<main class="content">

606

<!-- Render the actual markdown content -->

607

<Content />

608

</main>

609

610

<footer v-if="frontmatter.showFooter !== false">

611

<p v-if="page.lastUpdated">

612

Last updated: {{ new Date(page.lastUpdated).toLocaleDateString() }}

613

</p>

614

</footer>

615

</div>

616

</template>

617

618

<style scoped>

619

.content-wrapper {

620

display: grid;

621

grid-template-columns: 1fr 200px;

622

gap: 2rem;

623

}

624

625

.table-of-contents {

626

position: sticky;

627

top: 2rem;

628

height: fit-content;

629

}

630

</style>

631

```

632

633

### Advanced Client Utilities

634

635

Additional utilities for advanced client-side functionality.

636

637

#### Custom Data Loading

638

639

```typescript { .api }

640

/**

641

* Load custom data in client components

642

*/

643

interface DataLoader<T> {

644

/**

645

* Load data for current page

646

*/

647

load(): Promise<T>;

648

649

/**

650

* Cache loaded data

651

*/

652

cache?: boolean;

653

654

/**

655

* Invalidate cache conditions

656

*/

657

invalidate?: (route: Route) => boolean;

658

}

659

660

/**

661

* Create data loader for client components

662

*/

663

function createDataLoader<T>(loader: DataLoader<T>): () => Promise<T>;

664

```

665

666

#### Client-Side Search

667

668

```typescript { .api }

669

/**

670

* Client-side search functionality

671

*/

672

interface SearchProvider {

673

/**

674

* Search query

675

*/

676

search(query: string): Promise<SearchResult[]>;

677

678

/**

679

* Initialize search index

680

*/

681

initialize(): Promise<void>;

682

683

/**

684

* Update search index

685

*/

686

update(pages: PageData[]): Promise<void>;

687

}

688

689

interface SearchResult {

690

/**

691

* Page title

692

*/

693

title: string;

694

695

/**

696

* Page URL

697

*/

698

url: string;

699

700

/**

701

* Search excerpt

702

*/

703

excerpt: string;

704

705

/**

706

* Search relevance score

707

*/

708

score: number;

709

}

710

```