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

theming.mddocs/

0

# Theme System API

1

2

VitePress theming system provides a Vue-based theme architecture with a comprehensive default theme, composables for state management, and extensive customization options. Themes can be extended, replaced, or enhanced with custom functionality.

3

4

## Capabilities

5

6

### Theme Structure

7

8

Core theme interfaces and structure for creating custom themes.

9

10

#### Theme Interface

11

12

Main theme object structure that defines how themes are implemented.

13

14

```typescript { .api }

15

/**

16

* Theme object structure for VitePress themes

17

*/

18

interface Theme {

19

/**

20

* Main layout component (required for custom themes)

21

*/

22

Layout?: Component;

23

24

/**

25

* App enhancement function for registering components, plugins, etc.

26

*/

27

enhanceApp?: (ctx: EnhanceAppContext) => Awaitable<void>;

28

29

/**

30

* Parent theme to extend from

31

*/

32

extends?: Theme;

33

34

/**

35

* @deprecated Use Layout component and check useData().page.value.isNotFound

36

* Custom 404 Not Found component

37

*/

38

NotFound?: Component;

39

40

/**

41

* @deprecated Wrap your Layout component instead

42

* Setup function called during app initialization

43

*/

44

setup?: () => void;

45

}

46

47

interface EnhanceAppContext {

48

/**

49

* Vue app instance

50

*/

51

app: App;

52

53

/**

54

* VitePress router instance

55

*/

56

router: Router;

57

58

/**

59

* Reactive site data

60

*/

61

siteData: Ref<SiteData>;

62

}

63

```

64

65

**Usage Examples:**

66

67

```typescript

68

// Custom theme example

69

import DefaultTheme from "vitepress/theme";

70

import CustomLayout from "./CustomLayout.vue";

71

import CustomComponent from "./components/CustomComponent.vue";

72

73

const customTheme: Theme = {

74

extends: DefaultTheme,

75

Layout: CustomLayout,

76

enhanceApp(ctx) {

77

// Register custom components globally

78

ctx.app.component("CustomComponent", CustomComponent);

79

80

// Add custom plugins

81

ctx.app.use(CustomPlugin);

82

83

// Add global properties

84

ctx.app.config.globalProperties.$customUtility = customUtility;

85

86

// Router hooks

87

ctx.router.onBeforeRouteChange = (to) => {

88

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

89

};

90

}

91

};

92

93

export default customTheme;

94

```

95

96

### Default Theme

97

98

VitePress default theme with comprehensive component library and configuration options.

99

100

#### Default Theme Export

101

102

The main default theme object with Layout and app enhancement.

103

104

```typescript { .api }

105

/**

106

* VitePress default theme

107

*/

108

declare const DefaultTheme: Theme & {

109

/**

110

* Main layout component

111

*/

112

Layout: Component;

113

114

/**

115

* App enhancement function

116

*/

117

enhanceApp: (ctx: EnhanceAppContext) => void;

118

};

119

```

120

121

**Usage Examples:**

122

123

```typescript

124

// Use default theme as-is

125

import DefaultTheme from "vitepress/theme";

126

export default DefaultTheme;

127

128

// Extend default theme

129

import DefaultTheme from "vitepress/theme";

130

import "./custom-styles.css";

131

132

export default {

133

extends: DefaultTheme,

134

enhanceApp(ctx) {

135

// Call parent enhanceApp

136

DefaultTheme.enhanceApp?.(ctx);

137

138

// Add custom enhancements

139

ctx.app.component("MyCustomComponent", MyCustomComponent);

140

}

141

};

142

143

// Replace default theme layout

144

import DefaultTheme from "vitepress/theme";

145

import CustomLayout from "./CustomLayout.vue";

146

147

export default {

148

...DefaultTheme,

149

Layout: CustomLayout

150

};

151

```

152

153

### Default Theme Configuration

154

155

Comprehensive configuration interface for the default theme.

156

157

#### DefaultTheme.Config

158

159

Configuration interface for customizing the default theme appearance and behavior.

160

161

```typescript { .api }

162

/**

163

* Configuration interface for VitePress default theme

164

*/

165

interface DefaultTheme.Config {

166

/**

167

* Site logo configuration

168

*/

169

logo?: ThemeableImage;

170

171

/**

172

* Custom logo link override

173

*/

174

logoLink?: string | {

175

link?: string;

176

rel?: string;

177

target?: string;

178

};

179

180

/**

181

* Custom site title in navbar (overrides config.title)

182

*/

183

siteTitle?: string | false;

184

185

/**

186

* Navigation items in header

187

*/

188

nav?: NavItem[];

189

190

/**

191

* Sidebar configuration

192

*/

193

sidebar?: Sidebar;

194

195

/**

196

* Aside/outline configuration

197

*/

198

aside?: boolean | "left";

199

outline?: Outline | Outline["level"] | false;

200

201

/**

202

* Edit link configuration

203

*/

204

editLink?: EditLink;

205

206

/**

207

* Last updated configuration

208

*/

209

lastUpdated?: LastUpdatedOptions;

210

211

/**

212

* Document footer (prev/next) configuration

213

*/

214

docFooter?: DocFooter;

215

216

/**

217

* Social links in navigation

218

*/

219

socialLinks?: SocialLink[];

220

221

/**

222

* Footer configuration

223

*/

224

footer?: Footer;

225

226

/**

227

* Search configuration (local or Algolia)

228

*/

229

search?:

230

| { provider: "local"; options?: LocalSearchOptions }

231

| { provider: "algolia"; options: AlgoliaSearchOptions };

232

233

/**

234

* Carbon ads configuration

235

*/

236

carbonAds?: CarbonAdsOptions;

237

238

/**

239

* Internationalization routing

240

*/

241

i18nRouting?: boolean;

242

243

/**

244

* External link icon display

245

*/

246

externalLinkIcon?: boolean;

247

248

/**

249

* 404 page customization

250

*/

251

notFound?: NotFoundOptions;

252

253

/**

254

* UI text labels (for internationalization)

255

*/

256

darkModeSwitchLabel?: string;

257

lightModeSwitchTitle?: string;

258

darkModeSwitchTitle?: string;

259

sidebarMenuLabel?: string;

260

returnToTopLabel?: string;

261

langMenuLabel?: string;

262

skipToContentLabel?: string;

263

}

264

265

type ThemeableImage =

266

| string

267

| { src: string; alt?: string; [prop: string]: any }

268

| { light: string; dark: string; alt?: string; [prop: string]: any };

269

```

270

271

**Usage Examples:**

272

273

```typescript

274

// Complete default theme configuration

275

import { defineConfig } from "vitepress";

276

277

export default defineConfig({

278

title: "My Documentation",

279

themeConfig: {

280

logo: "/logo.svg",

281

siteTitle: "My Docs",

282

283

nav: [

284

{ text: "Guide", link: "/guide/" },

285

{ text: "API", link: "/api/" },

286

{

287

text: "Resources",

288

items: [

289

{ text: "Examples", link: "/examples/" },

290

{ text: "FAQ", link: "/faq/" }

291

]

292

}

293

],

294

295

sidebar: {

296

"/guide/": [

297

{

298

text: "Getting Started",

299

collapsed: false,

300

items: [

301

{ text: "Introduction", link: "/guide/" },

302

{ text: "Installation", link: "/guide/installation" }

303

]

304

}

305

]

306

},

307

308

editLink: {

309

pattern: "https://github.com/user/repo/edit/main/docs/:path",

310

text: "Edit this page"

311

},

312

313

socialLinks: [

314

{ icon: "github", link: "https://github.com/user/repo" },

315

{ icon: "twitter", link: "https://twitter.com/user" }

316

],

317

318

search: {

319

provider: "local",

320

options: {

321

translations: {

322

button: { buttonText: "Search" },

323

modal: { noResultsText: "No results found" }

324

}

325

}

326

}

327

}

328

});

329

```

330

331

### Theme Composables

332

333

Vue composables for accessing and managing theme state within components.

334

335

#### useSidebar

336

337

Composable for managing sidebar state and behavior.

338

339

```typescript { .api }

340

/**

341

* Access sidebar state and controls

342

* @returns DocSidebar object with sidebar state and methods

343

*/

344

function useSidebar(): DefaultTheme.DocSidebar;

345

346

interface DefaultTheme.DocSidebar {

347

/**

348

* Whether sidebar is open (mobile)

349

*/

350

isOpen: Ref<boolean>;

351

352

/**

353

* Computed sidebar items for current route

354

*/

355

sidebar: ComputedRef<SidebarItem[]>;

356

357

/**

358

* Sidebar groups (same as sidebar but different name for compatibility)

359

*/

360

sidebarGroups: ComputedRef<SidebarItem[]>;

361

362

/**

363

* Whether current page has sidebar

364

*/

365

hasSidebar: ComputedRef<boolean>;

366

367

/**

368

* Whether current page has aside/outline

369

*/

370

hasAside: ComputedRef<boolean>;

371

372

/**

373

* Whether aside is positioned on the left

374

*/

375

leftAside: ComputedRef<boolean>;

376

377

/**

378

* Whether sidebar is enabled for current route

379

*/

380

isSidebarEnabled: ComputedRef<boolean>;

381

382

/**

383

* Open sidebar (mobile)

384

*/

385

open(): void;

386

387

/**

388

* Close sidebar (mobile)

389

*/

390

close(): void;

391

392

/**

393

* Toggle sidebar (mobile)

394

*/

395

toggle(): void;

396

}

397

```

398

399

**Usage Examples:**

400

401

```vue

402

<script setup>

403

import { useSidebar } from "vitepress/theme";

404

405

const {

406

isOpen,

407

sidebar,

408

hasSidebar,

409

hasAside,

410

open,

411

close,

412

toggle

413

} = useSidebar();

414

415

// Custom sidebar component

416

const handleItemClick = () => {

417

// Close mobile sidebar after navigation

418

if (window.innerWidth < 768) {

419

close();

420

}

421

};

422

</script>

423

424

<template>

425

<aside v-if="hasSidebar" class="custom-sidebar" :class="{ open: isOpen }">

426

<button @click="toggle" class="sidebar-toggle">

427

{{ isOpen ? 'Close' : 'Open' }} Menu

428

</button>

429

430

<nav class="sidebar-nav">

431

<div v-for="item in sidebar" :key="item.text" class="sidebar-group">

432

<h3 v-if="item.text">{{ item.text }}</h3>

433

<ul v-if="item.items">

434

<li v-for="child in item.items" :key="child.link">

435

<a :href="child.link" @click="handleItemClick">

436

{{ child.text }}

437

</a>

438

</li>

439

</ul>

440

</div>

441

</nav>

442

</aside>

443

</template>

444

```

445

446

#### useLocalNav

447

448

Composable for managing local navigation (table of contents) state.

449

450

```typescript { .api }

451

/**

452

* Access local navigation (outline) state

453

* @returns DocLocalNav object with headers and visibility state

454

*/

455

function useLocalNav(): DefaultTheme.DocLocalNav;

456

457

interface DefaultTheme.DocLocalNav {

458

/**

459

* Page outline headers

460

*/

461

headers: ShallowRef<Header[]>;

462

463

/**

464

* Whether local nav should be shown

465

*/

466

hasLocalNav: ComputedRef<boolean>;

467

}

468

```

469

470

**Usage Examples:**

471

472

```vue

473

<script setup>

474

import { useLocalNav, useData } from "vitepress/theme";

475

476

const { headers, hasLocalNav } = useLocalNav();

477

const { page } = useData();

478

479

// Custom table of contents component

480

const activeHeader = ref("");

481

482

// Track active header on scroll

483

onMounted(() => {

484

const observer = new IntersectionObserver((entries) => {

485

for (const entry of entries) {

486

if (entry.isIntersecting) {

487

activeHeader.value = entry.target.id;

488

}

489

}

490

});

491

492

// Observe all headers

493

headers.value.forEach(header => {

494

const element = document.getElementById(header.slug);

495

if (element) observer.observe(element);

496

});

497

});

498

</script>

499

500

<template>

501

<nav v-if="hasLocalNav" class="local-nav">

502

<h4>On This Page</h4>

503

<ul>

504

<li

505

v-for="header in headers"

506

:key="header.slug"

507

:class="{

508

active: activeHeader === header.slug,

509

[`level-${header.level}`]: true

510

}"

511

>

512

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

513

514

<!-- Nested headers -->

515

<ul v-if="header.children?.length">

516

<li

517

v-for="child in header.children"

518

:key="child.slug"

519

:class="{ active: activeHeader === child.slug }"

520

>

521

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

522

</li>

523

</ul>

524

</li>

525

</ul>

526

</nav>

527

</template>

528

```

529

530

### Default Theme Components

531

532

Comprehensive set of Vue components provided by the default theme.

533

534

#### Layout Components

535

536

Main layout and page structure components.

537

538

```typescript { .api }

539

/**

540

* Home page content area component

541

*/

542

declare const VPHomeContent: Component;

543

544

/**

545

* Home page features section component

546

*/

547

declare const VPHomeFeatures: Component<{

548

features: Feature[];

549

}>;

550

551

/**

552

* Home page hero section component

553

*/

554

declare const VPHomeHero: Component<{

555

name?: string;

556

text?: string;

557

tagline?: string;

558

image?: ThemeableImage;

559

actions?: HeroAction[];

560

}>;

561

562

/**

563

* Home page sponsors section component

564

*/

565

declare const VPHomeSponsors: Component<{

566

message?: string;

567

sponsors: Sponsor[];

568

}>;

569

570

/**

571

* Team page wrapper component

572

*/

573

declare const VPTeamPage: Component;

574

575

/**

576

* Team page section component

577

*/

578

declare const VPTeamPageSection: Component<{

579

title?: string;

580

lead?: string;

581

members: TeamMember[];

582

}>;

583

584

/**

585

* Team page title component

586

*/

587

declare const VPTeamPageTitle: Component<{

588

title: string;

589

lead?: string;

590

}>;

591

592

/**

593

* Team members grid component

594

*/

595

declare const VPTeamMembers: Component<{

596

size?: "small" | "medium";

597

members: TeamMember[];

598

}>;

599

```

600

601

#### UI Components

602

603

Reusable UI components for custom layouts and content.

604

605

```typescript { .api }

606

/**

607

* Badge/tag component for highlighting information

608

*/

609

declare const VPBadge: Component<{

610

type?: "info" | "tip" | "warning" | "danger";

611

text: string;

612

}>;

613

614

/**

615

* Button component with theme styling

616

*/

617

declare const VPButton: Component<{

618

tag?: string | Component;

619

size?: "medium" | "big";

620

theme?: "brand" | "alt" | "sponsor";

621

text: string;

622

href?: string;

623

}>;

624

625

/**

626

* Features showcase component

627

*/

628

declare const VPFeatures: Component<{

629

features: Feature[];

630

}>;

631

632

/**

633

* Responsive image component with theme support

634

*/

635

declare const VPImage: Component<{

636

image: ThemeableImage;

637

alt?: string;

638

}>;

639

640

/**

641

* Enhanced link component with external link detection

642

*/

643

declare const VPLink: Component<{

644

tag?: string | Component;

645

href?: string;

646

noIcon?: boolean;

647

target?: string;

648

rel?: string;

649

}>;

650

651

/**

652

* Sponsors display component

653

*/

654

declare const VPSponsors: Component<{

655

mode: "normal" | "aside";

656

tier: string;

657

size?: "big" | "medium" | "small" | "xmini";

658

data: Sponsor[];

659

}>;

660

```

661

662

#### Navigation Components

663

664

Components for navigation menus and search functionality.

665

666

```typescript { .api }

667

/**

668

* Navigation bar search component

669

*/

670

declare const VPNavBarSearch: Component;

671

672

/**

673

* Social media link component

674

*/

675

declare const VPSocialLink: Component<{

676

icon: SocialLinkIcon;

677

link: string;

678

ariaLabel?: string;

679

}>;

680

681

/**

682

* Social media links group component

683

*/

684

declare const VPSocialLinks: Component<{

685

links: SocialLink[];

686

}>;

687

```

688

689

#### Documentation Components

690

691

Components specific to documentation layouts.

692

693

```typescript { .api }

694

/**

695

* Aside sponsors section component

696

*/

697

declare const VPDocAsideSponsors: Component<{

698

tier: string;

699

size?: "big" | "medium" | "small";

700

data: Sponsor[];

701

}>;

702

```

703

704

**Usage Examples:**

705

706

```vue

707

<script setup>

708

import {

709

VPHomeHero,

710

VPHomeFeatures,

711

VPTeamMembers,

712

VPButton,

713

VPBadge

714

} from "vitepress/theme";

715

716

// Hero configuration

717

const heroConfig = {

718

name: "My Project",

719

text: "Next Generation Tool",

720

tagline: "Fast, reliable, and easy to use",

721

image: {

722

src: "/hero-logo.svg",

723

alt: "My Project Logo"

724

},

725

actions: [

726

{

727

theme: "brand",

728

text: "Get Started",

729

link: "/guide/getting-started"

730

},

731

{

732

theme: "alt",

733

text: "View on GitHub",

734

link: "https://github.com/user/project"

735

}

736

]

737

};

738

739

// Features configuration

740

const features = [

741

{

742

icon: "⚡",

743

title: "Fast Performance",

744

details: "Optimized for speed and efficiency"

745

},

746

{

747

icon: "🔧",

748

title: "Easy Configuration",

749

details: "Simple setup with sensible defaults"

750

}

751

];

752

753

// Team members

754

const teamMembers = [

755

{

756

avatar: "/avatars/john.jpg",

757

name: "John Doe",

758

title: "Lead Developer",

759

links: [

760

{ icon: "github", link: "https://github.com/johndoe" }

761

]

762

}

763

];

764

</script>

765

766

<template>

767

<div class="custom-layout">

768

<!-- Hero section -->

769

<VPHomeHero v-bind="heroConfig" />

770

771

<!-- Features section -->

772

<VPHomeFeatures :features="features" />

773

774

<!-- Team section -->

775

<section class="team-section">

776

<h2>Meet the Team</h2>

777

<VPTeamMembers size="medium" :members="teamMembers" />

778

</section>

779

780

<!-- Custom content with theme components -->

781

<section class="custom-content">

782

<h2>

783

Latest Release

784

<VPBadge type="tip" text="v2.0" />

785

</h2>

786

787

<p>Check out our latest features and improvements.</p>

788

789

<VPButton

790

theme="brand"

791

text="Download Now"

792

href="/download"

793

/>

794

</section>

795

</div>

796

</template>

797

```

798

799

### Theme Types

800

801

Supporting type definitions for theme configuration and components.

802

803

#### Navigation Types

804

805

```typescript { .api }

806

type NavItem = NavItemComponent | NavItemWithLink | NavItemWithChildren;

807

808

interface NavItemComponent {

809

component: string;

810

props?: Record<string, any>;

811

}

812

813

interface NavItemWithLink {

814

text: string;

815

link: string;

816

activeMatch?: string;

817

rel?: string;

818

target?: string;

819

noIcon?: boolean;

820

}

821

822

interface NavItemWithChildren {

823

text?: string;

824

items: (NavItemComponent | NavItemChildren | NavItemWithLink)[];

825

activeMatch?: string;

826

}

827

828

interface NavItemChildren {

829

text?: string;

830

items: NavItemWithLink[];

831

}

832

```

833

834

#### Sidebar Types

835

836

```typescript { .api }

837

type Sidebar = SidebarItem[] | SidebarMulti;

838

839

interface SidebarMulti {

840

[path: string]: SidebarItem[] | { items: SidebarItem[]; base: string };

841

}

842

843

interface SidebarItem {

844

text?: string;

845

link?: string;

846

items?: SidebarItem[];

847

collapsed?: boolean;

848

base?: string;

849

docFooterText?: string;

850

rel?: string;

851

target?: string;

852

}

853

```

854

855

#### Feature and Team Types

856

857

```typescript { .api }

858

interface Feature {

859

icon?: FeatureIcon;

860

title: string;

861

details: string;

862

link?: string;

863

linkText?: string;

864

rel?: string;

865

target?: string;

866

}

867

868

type FeatureIcon =

869

| string

870

| { src: string; alt?: string; width?: string; height?: string; wrap?: boolean }

871

| { light: string; dark: string; alt?: string; width?: string; height?: string; wrap?: boolean };

872

873

interface TeamMember {

874

avatar: string;

875

name: string;

876

title?: string;

877

org?: string;

878

orgLink?: string;

879

desc?: string;

880

links?: SocialLink[];

881

sponsor?: string;

882

actionText?: string;

883

}

884

885

interface SocialLink {

886

icon: SocialLinkIcon;

887

link: string;

888

ariaLabel?: string;

889

}

890

891

type SocialLinkIcon = string | { svg: string };

892

```