From Default to Custom: Building a VitePress Blog Theme

- Lire en français
Resources: garabit

In the previous article, we initialized our project using the VitePress template. By default, VitePress comes with a built-in theme designed for creating documentation websites. However, we aim to develop a blog site, necessitating the creation of a custom theme.

Default VitePress Theme, not suitable for our blog site.
Default VitePress Theme, not suitable for our blog site.

Custom Theme

To construct a custom theme, two files need to be created:

  • src/.vitepress/theme/index.ts: This serves as the entry point for our custom theme, comparable to the main.ts file in a Vite + Vue project.
  • src/.vitepress/theme/Layout.vue: This file constitutes the main Vue component of our custom theme, analogous to the App.vue file in a Vite + Vue project.

We've established a theme folder within the .vitepress directory. This is the designated location for all files associated with our custom theme. It can be viewed similarly to the src folder in a Vite + Vue project and will adopt a parallel structure. Further explanation will be provided in the forthcoming article.

File index.ts

The index.ts file is automatically recognized by VitePress and, like the main.ts file in a Vite + Vue project, it is required to load the Layout.vue file.

ts
import { Theme } from 'vitepress'
import Layout from './Layout.vue'

export default {
  Layout,
} satisfies Theme

Tip

Within the exported object, the Vue application can be accessed and configured using enhanceApp. This is useful for incorporating global components, directives, or plugins. In our current context, its utilization is unnecessary.

File Layout.vue

To begin, we can simply insert an h1 element with the text "Garabit Blog" into the Layout.vue file.

vue
<template>
  <div>
    <h1>Garabit Blog</h1>
  </div>
</template>

To initiate the development server, run the following command:

bash
pnpm run docs:dev

Note

The docs: prefix exists because VitePress is engineered to integrate into pre-existing projects without the necessity for a monorepo. This prefix distinguishes VitePress commands and helps prevent conflicts with existing project commands. We will modify this aspect later, as it isn't essential for our purposes.

Navigate to http://localhost:5173 to witness our custom theme operational.

Splendid!

Displaying Markdown Content

This marks a promising beginning, yet we need to render the markdown content to enhance our blog's functionality. For this purpose, the Content component provided by VitePress is instrumental.

vue
<template>
  <div>
    <h1>Garabit Blog</h1>

    <Content />
  </div>
</template>

This component will automatically render the markdown content of the current page. As of now, it shows nothing because the index.md content is empty. Remove all the front matter and add some text:

md
Hey 👋,

This is the index page.

A pivotal feature of VitePress is its approach to handling routing. By default, the index.md file represents the homepage. Thus, navigating to http://localhost:5173 will display the index.md file content. Additional markdown files are accessible by their filenames. For instance, about.md is accessible via http://localhost:5173/about.html. To link to a different page, use the a tag with the href attribute pointing to the filename.

md
Hey 👋,

This is the index page.

[Go to the api-examples page](/api-examples)

Upon clicking the link, the page won't reload; instead, the content refreshes. This feature of VitePress facilitates seamless navigation.

Note

VitePress does not employ Vue Router. Instead, it utilizes a bespoke router specifically optimized for content-centric websites.

The video above demonstrates that the page remains unreloaded when navigating between pages. The 'arrow', situated left of the house icon, indicates page updates without reloading. Otherwise, the arrow would display as a cross.

Removing the Default Theme

With the foundational elements for a custom theme now established, we can eliminate aspects of the default theme.

Begin by removing the link in the index.md file:

md
Hey 👋,

This is the index page.

[Go to the api-examples page](/api-examples)

Subsequently, delete the api-examples.md and markdown-examples.md files from the root directory.

Lastly, eliminate related theme lines from the config.mts file:

ts
import Components from 'unplugin-vue-components/vite'
import { defineConfig } from 'vitepress'

export default defineConfig({
  title: 'My Awesome Project', 
  description: 'A VitePress Site', 
  themeConfig: { 
    // https://vitepress.dev/reference/default-theme-config
    nav: [ 
      { text: 'Home', link: '/' }, 
      { text: 'Examples', link: '/markdown-examples' }, 
    ], 

    sidebar: [ 
      { 
        text: 'Examples', 
        items: [ 
          { text: 'Markdown Examples', link: '/markdown-examples' }, 
          { text: 'Runtime API Examples', link: '/api-examples' }, 
        ], 
      }, 
    ], 

    socialLinks: [ 
      { icon: 'github', link: 'https://github.com/vuejs/vitepress' }, 
    ], 
  }, 

  vite: {
    plugins: [Components()],
  },
})

We are now fully equipped and poised to create our custom theme.