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
```