How to build modern docs with vitepress
VitePress is a simple and performant static site generator built on top of Vite for creating docs in a matter of minutes...
ilosrim | 2022/01/05
Definition
VitePress is a simple and performant static site generator built on top of Vite for creating docs in a matter of minutes. It is powered by Vuejs, and Vite with built in customizable components. VitePress powers some popular documentation sites like Vuejs, Vitest, faker.js, and Vite itself.
Prerequisites
To follow along with this tutorial, you need to have a basic understanding of the following:
- Markdown syntax
- Brief understanding of NPM and Vite
Here's a screenshot of what you'll be building at the end of this tutorial.
Step. 1: Create a new project
If you already have a folder created, you can skip this step to the next one if not, use the following command to create a project folder and move into the folder.
mkdir project-name
cd project-name
mkdir project-name
cd project-name
Next you need to initialize with your preferred package manager. I'll be using NPM for the rest of this guide.
npm init
// or use this command if you want to skip all the questions
npm init -y
npm init
// or use this command if you want to skip all the questions
npm init -y
If you used the first command, you'll be prompted with certain questions, complete them as appropriate. After a successful operation, you should have a package.json file in your root directory; This is where the VitePress dev dependency will be installed.
Step. 2: Install VitePress
Next step is to add VitePress and Vue as dev dependencies to your project.
You've successfully installed VitePress and Vue and added it as a dev dependency. Now you can start creating creating your respective doc files, but before you do that, I believe it's essential to explain how VitePress works.
How does VitePress work?
VitePress makes use of Markdown .md
files for it's markup which is automatically converted into static HTML. In other for this to work, a special folder called docs
is created in the root directory.
This folder behaves similar to the pages
folder in NextJS, where any .js
file created in the directory is automatically treated as a web page. In this case a file called index.md
will be the treated as index.html
and serve as the root of your docs template.
Now you understand how that works, you can now create your respective doc files.
Step 3. Create respective files
You can create the docs folder and the index.md file manually, or you can do it with the terminal like a hacker.
mkdir docs && echo '# Hello VitePress' > docs/index.md
mkdir docs && echo '# Hello VitePress' > docs/index.md
This command is simply creating a folder called docs and adding an index.md file containing a h1 element that says, "Hello World".
With this, you can boot up your dev environment to see what has been created so far.
Step 4: Boot up dev environment
In other to run your docs locally, you need to add the following scripts inside the package.json file. Simply copy the code below and replace it with the "script" object.
// package.json
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:serve": "vitepress serve docs"
},
// package.json
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:serve": "vitepress serve docs"
},
Finally, the documentation site can be served on a local server by running the command below:
npm run docs:dev
npm run docs:dev
This will start a hot-reloading development server at http://localhost:5173
, and you can visit it to see your docs site.
Output
All you had to do was add the markup and VitePress handled the looks from it's template engine. In the next session, you'll learn how you can customize the docs to fit your needs.
How to customize your docs
First create a .vitepress
folder inside the docs directory you created earlier on. This is where all VitePress-specific files will be placed. Inside this new directory, you need a config.js
file. Again, you can use the terminal command as a hacker.
mkdir .vitepress && touch .vitepress/config.js
mkdir .vitepress && touch .vitepress/config.js
To test this config file, you can start by changing the meta title and description of your docs site. Copy this markup and paste into the config.j
s file.
// .vitepress/config.js
export default {
title: "Adocs",
description: "An awesome docs template built by me",
};
// .vitepress/config.js
export default {
title: "Adocs",
description: "An awesome docs template built by me",
};
If you check the dev tools, you should see the changes in the meta title and description.
Title and Logo
In other to change the logo title and add an image, copy the markup below and paste it into a new object called themeConfig
inside the same config.js
file. This will overwrite the current title and add a logo your docs site.
// config.js
export default {
themeConfig: {
logo: "/logo.svg",
siteTitle: "Adocs",
},
};
// config.js
export default {
themeConfig: {
logo: "/logo.svg",
siteTitle: "Adocs",
},
};
For the image source, you can pass in an image URL or specify the path to a local image. To do it locally, make sure you place the image within the public
directory.
Output
WARNING
Note: files in the public directory are served at the root path. So instead of ../public/logo.svg
, just use /logo.svg
.
Navbar
Customizing the Navbar
is a pretty straightforward process as well. Inside your themeConfig
file, paste the markup below. Here we have an object that contains two properties. The anchor text text
, and the path, link
defines the URL path.
// .vitepress/config.js
{
// ...
nav: [
{ text: "About", link: "/about" },
{ text: "Contact", link: "/contact" },
{ text: "Guide", link: "/guide" },
{ text: "Configs", link: "/configs" },
{ text: "Changelog", link: "https://github.com/Evavic44" },
],
// ...
}
// .vitepress/config.js
{
// ...
nav: [
{ text: "About", link: "/about" },
{ text: "Contact", link: "/contact" },
{ text: "Guide", link: "/guide" },
{ text: "Configs", link: "/configs" },
{ text: "Changelog", link: "https://github.com/Evavic44" },
],
// ...
}
Essentially navigating to http://localhost:5173/about
should take you to an about page(though we haven't created that yet).
Output
Navigation links can also be dropdown menus too. To add one, simply replace any of the links property with the items object which contains an array of links.
// .vitepress/config.js
{
text: "Changelog",
items: [
{ text: "v0.0.1", link: "/item-1" },
{ text: "v0.0.2", link: "/item-2" },
{ text: "v0.0.3", link: "/item-3" },
],
},
// .vitepress/config.js
{
text: "Changelog",
items: [
{ text: "v0.0.1", link: "/item-1" },
{ text: "v0.0.2", link: "/item-2" },
{ text: "v0.0.3", link: "/item-3" },
],
},
Now changelog will become a dropdown menu with the respective links you pass inside.
Output
Social Icons
Navigation menus usually have social icons visitors can use to visit your social platforms. To add that, define a new object called socialLinks inside themeConfig and simply pass in the social icon and the link you want it to navigate to.
// .vitepress/config.js
socialLinks: [
{ icon: "github", link: "https://github.com/Evavic44/adocs" },
{ icon: "twitter", link: "https://twitter.com/victorekea" },
{ icon: "discord", link: "", target: "_blank" },
];
// .vitepress/config.js
socialLinks: [
{ icon: "github", link: "https://github.com/Evavic44/adocs" },
{ icon: "twitter", link: "https://twitter.com/victorekea" },
{ icon: "discord", link: "", target: "_blank" },
];
By default only 7 popular icons are provided. If you want to add a custom icon, use the SVG property to define an svg image.
}
"discord"
"facebook"
"github"
"instagram"
"linkedin"
"slack"
"twitter"
"youtube"
{ svg: string };
{
}
"discord"
"facebook"
"github"
"instagram"
"linkedin"
"slack"
"twitter"
"youtube"
{ svg: string };
{
WARNING
For the SVG icon, make sure you add the role="img" property, this allows the string convert it properly.
Sidebar
VitePress also comes with built-in components like sidebar menus. To add a sidebar, create an object called sidebar and inside we add nested objects that takes in three values; the nested title, collapsible functionality (Default is set to true) and the nested links.
// .vitepress/config.js
sidebar: [
{
text: "Section A",
collapsible: true,
items: [
{ text: "Introduction", link: "/introduction" },
{ text: "Getting Started", link: "/getting-started" },
],
},
{
text: "Section B",
collapsible: false,
items: [
{ text: "Introduction", link: "/introduction" },
{ text: "Getting Started", link: "/getting-started" },
],
},
{
text: "Section C",
collapsible: true,
items: [
{ text: "Introduction", link: "/introduction" },
{ text: "Getting Started", link: "/getting-started" },
],
},
],
// .vitepress/config.js
sidebar: [
{
text: "Section A",
collapsible: true,
items: [
{ text: "Introduction", link: "/introduction" },
{ text: "Getting Started", link: "/getting-started" },
],
},
{
text: "Section B",
collapsible: false,
items: [
{ text: "Introduction", link: "/introduction" },
{ text: "Getting Started", link: "/getting-started" },
],
},
{
text: "Section C",
collapsible: true,
items: [
{ text: "Introduction", link: "/introduction" },
{ text: "Getting Started", link: "/getting-started" },
],
},
],
By adding collapsible: "true" to the sidebar object, it shows a toggle button to hide/show each section. You can create as much sections as you want.
Output
You can see section B is not collapsible and we have that aesthetic next page button on the bottom of the page.
Page Routing
As explained earlier, VitePress automatically converts every .md
file inside the root of the docs directory to static html that can be accessed in the address bar. For instance the index.md
is converted to index.html
, and about.md
, about.html and so on.
Since you've created your nav links and pointed them to their respective URLs, you can access these pages easily by creating them.
docs/
├── .vitepress/
│ └── config.js
├── public/
│ └── logo.svg
├── about.md
├── contact.md
├── guide.md
├── configs.md
└── get-started.md
docs/
├── .vitepress/
│ └── config.js
├── public/
│ └── logo.svg
├── about.md
├── contact.md
├── guide.md
├── configs.md
└── get-started.md
Create these files inside your docs folder and add a simple markup inside them just to see how this works. This page is basic markdown so all your markdown syntax like links, code blocks, headings, etc works here.
Just for testing purposes, copy this markdown content and paste it inside any of the .md
file you just created.
# About
Welcome to the about page.
This markdown supports html elements like the `p` tag coupled with inline styles
<p style="color: #ff7340; border: 1px solid rgba(255, 135, 23, 0.25); border-radius:5px; padding: 1rem;">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.</p>
Even satire code snippets with syntax highlighting are also supported. 😅
const lang = prompt("What is your favorite programming language?");
(lang === "JavaScript") | (lang === "javascript") | (lang === "js")
? alert("JavaScript to the world! 🚀🟡")
: alert(`We don't permit such languages here 💩`);
Of course, images are not left out.
<img src="/logo.svg" alt="adocs logo">
# About
Welcome to the about page.
This markdown supports html elements like the `p` tag coupled with inline styles
<p style="color: #ff7340; border: 1px solid rgba(255, 135, 23, 0.25); border-radius:5px; padding: 1rem;">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.</p>
Even satire code snippets with syntax highlighting are also supported. 😅
const lang = prompt("What is your favorite programming language?");
(lang === "JavaScript") | (lang === "javascript") | (lang === "js")
? alert("JavaScript to the world! 🚀🟡")
: alert(`We don't permit such languages here 💩`);
Of course, images are not left out.
<img src="/logo.svg" alt="adocs logo">
Output
Great! You've set-up the docs, added a navigation menu with dropdown feature, added a sidebar, and customized the links to navigate to different pages. Next up, let's work on the home page.
Customizing the home page.
Just like every other components, VitePress provides us with markup for building the home page. I've broken it down into three parts: Hero, features, and footer section.
Hero Section
First, we'll start with the hero section. Replace the Hello World text in the index.md
page with the following markup.
# docs/index.md
---
layout: home
hero:
name: Adocs
text: Static docs template built with VitePress.
image:
src: /logo-big.svg
alt: Adocs logo
tagline: A free to use template for creating docs for your projects
actions:
- theme: brand
text: Get Started
link: /get-started
- theme: alt
text: View on GitHub
link: https://github.com/evavic44/adocs-template
---
# docs/index.md
---
layout: home
hero:
name: Adocs
text: Static docs template built with VitePress.
image:
src: /logo-big.svg
alt: Adocs logo
tagline: A free to use template for creating docs for your projects
actions:
- theme: brand
text: Get Started
link: /get-started
- theme: alt
text: View on GitHub
link: https://github.com/evavic44/adocs-template
---
Features Section
Additionally, you can also add a features section after the hero section. Simply paste the code below under the hero objects.
# /docs/index.md
---
link: https://github.com/evavic44/adocs-template
features:
- icon: ⚡️
title: Adocs, The DX that can't be beat
details: Lorem ipsum...
- icon: 🎉
title: Power of Vue meets Markdown
details: Lorem ipsum...
- icon: 🔥
title: Simple and minimal, always
details: Lorem ipsum...
- icon: 🎀
title: Stylish and cool
details: Lorem ipsum...
---
# /docs/index.md
---
link: https://github.com/evavic44/adocs-template
features:
- icon: ⚡️
title: Adocs, The DX that can't be beat
details: Lorem ipsum...
- icon: 🎉
title: Power of Vue meets Markdown
details: Lorem ipsum...
- icon: 🔥
title: Simple and minimal, always
details: Lorem ipsum...
- icon: 🎀
title: Stylish and cool
details: Lorem ipsum...
---
Output
Footer
You can add a footer message on the bottom of the page but this will only show up in the home page.
WARNING
The footer will not be displayed when the SideBar is visible. To add the footer component, go to the config.js file
and paste the markup inside the themeConfig
object
// .vitepress/config.js
footer: {
message: "Released under the MIT License.",
copyright: "Copyright © 2022-present Adocs",
},
// .vitepress/config.js
footer: {
message: "Released under the MIT License.",
copyright: "Copyright © 2022-present Adocs",
},
Output
Aside from the markup, you can also customize the components using custom CSS to change things like fonts family, colors, layout, ETC.
Custom CSS
The default theme CSS is customized by overriding root level CSS variables. If you want, you can check out the full list of css variables customizable.
To do get started, create a .vitepress/theme directory
, and inside this theme folder, add an index.js
and custom.css
file. If you've been following along, you can use the terminal command below to do this quickly.
mkdir docs/.vitepress/theme && touch docs/.vitepress/theme/index.js && touch docs/.vitepress/theme/custom.css
mkdir docs/.vitepress/theme && touch docs/.vitepress/theme/index.js && touch docs/.vitepress/theme/custom.css
If you ran into any issues with the terminal command, just create the files manually and move on to the next step.
Here's an overview of the folder structure.
docs/
├── .vitepress/
│ ├── config.js
│ └── theme/
│ ├── index.js
│ └── custom.css
├── public/
│ └── logo.svg
├── about.md
├── contact.md
├── guide.md
├── configs.md
└── get-started.md
docs/
├── .vitepress/
│ ├── config.js
│ └── theme/
│ ├── index.js
│ └── custom.css
├── public/
│ └── logo.svg
├── about.md
├── contact.md
├── guide.md
├── configs.md
└── get-started.md
After creating these files, inside the .vitepress/theme/index.js file
, paste the import commands.
// .vitepress/theme/index.js
import DefaultTheme from "vitepress/theme";
import "./custom.css";
export default DefaultTheme;
// .vitepress/theme/index.js
import DefaultTheme from "vitepress/theme";
import "./custom.css";
export default DefaultTheme;
Color Theme
The colors are controlled by the CSS variables. You can simply replace them with any colors you want.
TIP
This color has a provision for both light and dark mode. So make sure you change them accordingly.
Here's an example of my custom colors
/* .vitepress/theme/custom.css */
:root {
--vp-c-brand: rgb(255, 115, 64);
--vp-c-brand-light: rgb(255, 87, 25);
--vp-c-brand-lighter: rgb(255, 115, 64);
--vp-c-brand-dark: #ff622d;
--vp-c-brand-darker: rgb(226, 60, 0);
--vp-c-sponsor: #fd1d7c;
}
/* .vitepress/theme/custom.css */
:root {
--vp-c-brand: rgb(255, 115, 64);
--vp-c-brand-light: rgb(255, 87, 25);
--vp-c-brand-lighter: rgb(255, 115, 64);
--vp-c-brand-dark: #ff622d;
--vp-c-brand-darker: rgb(226, 60, 0);
--vp-c-sponsor: #fd1d7c;
}
If you don't see the effects immediately, try ending the server and starting it again.
Aside from the color themes, you can also override other things like, font family, typography, layout, breakpoints, etc.
Fonts
Google fonts can be imported inside the CSS file to override the default font family.
@import url(https://fonts.googleapis.com/css?family=Space+Mono:regular,italic,700,700italic);
@import url(https://fonts.googleapis.com/css?family=Space+Grotesk:regular,italic,700,700italic);
:root {
--vp-c-brand: #ff7340;
--vp-c-brand-light: #ff5719;
--vp-c-brand-lighter: #ff7340;
--vp-c-brand-lighter: rgba(255, 135, 23, 0.25);
--vp-c-brand-dark: #ff622d;
--vp-c-brand-darker: #e23c00;
--vp-c-sponsor: #fd1d7c;
/* Typography */
--vp-font-family-base: "Space Grotesk", "Inter var experimental", "Inter var",
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
"Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
/* Code Snippet font */
--vp-font-family-mono: "Space Mono", Menlo, Monaco, Consolas, "Courier New",
monospace;
}
@import url(https://fonts.googleapis.com/css?family=Space+Mono:regular,italic,700,700italic);
@import url(https://fonts.googleapis.com/css?family=Space+Grotesk:regular,italic,700,700italic);
:root {
--vp-c-brand: #ff7340;
--vp-c-brand-light: #ff5719;
--vp-c-brand-lighter: #ff7340;
--vp-c-brand-lighter: rgba(255, 135, 23, 0.25);
--vp-c-brand-dark: #ff622d;
--vp-c-brand-darker: #e23c00;
--vp-c-sponsor: #fd1d7c;
/* Typography */
--vp-font-family-base: "Space Grotesk", "Inter var experimental", "Inter var",
-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell,
"Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
/* Code Snippet font */
--vp-font-family-mono: "Space Mono", Menlo, Monaco, Consolas, "Courier New",
monospace;
}
With the --vp-font-family-base
variable you can change the main font and --vp-font-family-mono,
the font for code snippets.
Output
You've successfully customized the theme and changed the font family using CSS. Though there's more you can do in regards to styling, but at this point, I'm sure it's clearer how you can customize your docs with CSS. Let's discuss hosting in the next section.
Hosting
You can publish or host your docs site when you're done to different platforms like: Netlify, Vercel, AWS Amplify, etc.
First, run the build command
npm run docs:build
npm run docs:build
This should create a new dist folder that contains all the static files of your docs. In your hosting service, add these commands to their respective fields. Build command: npm run docs:build Output directory: docs/.vitepress/dist
This should create a new dist
folder that contains all the static files of your docs. In your hosting service, add these commands to their respective fields.
- Build command:
npm run docs:build
- Output directory:
docs/.vitepress/dist
After editing the settings, save, and deploy.
Conclusion
In this tutorial, you've set-up a full-fledged documentation site and customized it using CSS and VitePress built-in components. However, this tutorial only covers a fragment of what is possible with VitePress, to learn more, check out the VitePress docs.
Resources
If you are an open source ardent like myself or you enjoy hearing about such cool projects, do follow me on my socials so you don't miss my next post. Cheers. 🍷