Vocs is a React-based static documentation generator, powered by Vite. Write your content in Markdown or MDX, and Vocs will generate a static site with a default theme.
Scaffold a new project with the command line:
npm init vocs
- Install Vocs:
npm i vocs@next
- Add scripts to
package.json
:
{
"scripts": {
"docs:dev": "vocs dev",
"docs:build": "vocs build",
"docs:preview": "vocs preview"
}
}
- Create your first page:
my-project/
├── docs/
│ ├── pages/
│ │ └── index.mdx
├── node_modules/
└── package.json
- Run the development server:
npm run docs:dev
Visit http://localhost:5173
to see your documentation site.
A typical Vocs project structure looks like this:
my-project/
├── docs/
│ ├── pages/
│ │ ├── index.mdx
│ │ └── about.mdx
│ ├── public/
│ │ └── favicon.ico
│ └── vocs.config.ts
├── node_modules/
└── package.json
The main directories and files are:
docs/
: Root directory for documentationdocs/pages/
: Contains your documentation pagesdocs/public/
: Static assetsdocs/vocs.config.ts
: Configuration file
Vocs supports standard Markdown syntax plus additional features. Here's a comprehensive guide:
# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6
- Italics:
*asterisks*
or_underscores_
- Bold:
**asterisks**
or__underscores__
- Combined:
**asterisks and _underscores_**
- Strikethrough:
~~Scratch this~~
1. Ordered list item
2. Another item
- Unordered sub-list
- Nested sub-list
- Another sub-list item
3. Third ordered item
[Link text](URL)

```javascript
console.log("hello world")
```
- Titles: ```````bash [Terminal]````
- Line focus:
// [!code focus]
- Line highlights:
// [!code hl]
- Line numbers: Add
showLineNumbers
meta - Word focus:
// [!code word]
- Diffs:
// [!code ++]
and// [!code --]
:::code-group
```bash [npm]
npm i vocs
pnpm i vocs
:::
#### Callouts
```markdown
:::note
Note content
:::
:::warning
Warning content
:::
:::danger
Danger content
:::
| Header 1 | Header 2 | Header 3 |
|----------|:--------:|---------:|
| Left | Center | Right |
| aligned | aligned | aligned |
::::steps
### Step one
Content for step one
### Step two
Content for step two
::::
- Import and use React components
- Use JSX in markdown
- Export metadata with frontmatter
Vocs provides several built-in components that you can use throughout your documentation:
Displays author or authors in a specific format.
Displays blog posts within the blogDir
.
Display a Vocs-flavored button with three styles:
- Default Button
- Accent Button
- Link Button
Displays a callout with content.
Displays a "home page" section with customizable content including logos, descriptions, and call-to-action buttons.
Renders a list of sponsors defined in the Vocs config.
You can also create and use your own custom components by importing them in your MDX files.
Vocs comes with three built-in layouts: docs
, landing
, and minimal
. Each layout has its own styling and components.
The default layout for documentation pages. Includes:
- Edit page link
- Outline
- Footer navigation
---
layout: docs
---
# A docs page
This is a docs page.
Special layout for homepages without sidebar or documentation components.
---
layout: landing
---
This is a landing page.
Use the built-in <HomePage>
components for a templated home page:
---
layout: landing
---
import { HomePage } from 'vocs/components'
<HomePage.Root>
<HomePage.Logo />
<HomePage.Tagline>React Documentation Framework, powered by Vite</HomePage.Tagline>
<HomePage.InstallPackage name="vocs" type="init" />
<HomePage.Description>
Vocs is a minimal static documentation generator designed to supercharge your documentation workflow.
</HomePage.Description>
<HomePage.Buttons>
<HomePage.Button href="/docs" variant="accent">Get started</HomePage.Button>
<HomePage.Button href="https://github.com/wevm/vocs">GitHub</HomePage.Button>
</HomePage.Buttons>
</HomePage.Root>
A barebones layout without documentation components:
---
layout: minimal
---
# A minimal page
This page uses a minimal layout.
Control layout features through frontmatter:
---
showSidebar: false
showOutline: false
showLogo: false
---
---
layout: landing
content:
horizontalPadding: 0px
width: 100%
verticalPadding: 0px
---
Vocs uses a configuration file (vocs.config.ts
) to define global metadata for your documentation. This includes things like the site title, description, logo, sidebar, and more for your project.
The Vocs config should be defined in a vocs.config.ts
file at the root of your project:
viem/
├── docs/
├── node_modules/
├── src/
├── package.json
└── vocs.config.ts
- title (string): Documentation title
- description (string): General description for the documentation
- basePath (string): Base path for deployment (e.g., '/docs')
- baseUrl (string): Base URL for documentation
- blogDir (string): Path to blog pages relative to project root
- font (object): Configure font settings including Google Fonts
- iconUrl (string): Favicon URL
- logoUrl (string): Logo URL for sidebar and mobile nav
- sidebar (object): Navigation displayed on the sidebar
- socials (array): Social media links in top navigation
- theme (object): Theme configuration
- search (object): Search configuration
- markdown (object): Markdown processing configuration
Example Configuration:
import { defineConfig } from 'vocs'
export default defineConfig({
title: 'My Docs',
description: 'Documentation for my awesome project',
basePath: '/docs',
baseUrl: 'https://example.com',
sidebar: [
{
text: 'Getting Started',
link: '/docs',
},
{
text: 'API',
collapsed: true,
items: [
{
text: 'Config',
link: '/docs/api/config',
},
],
}
],
socials: [
{
icon: 'github',
link: 'https://github.com/username/project',
},
],
theme: {
accentColor: '#ff0000',
}
})
Theming in Vocs is highly configurable. You can customize your documentation through CSS variables in the configuration file or via CSS classes.
import { defineConfig } from 'vocs'
export default defineConfig({
theme: {
accentColor: '#ff0000', // Single color
// OR
accentColor: {
light: 'black',
dark: 'white',
},
// OR
accentColor: {
backgroundAccent: { light: 'white', dark: 'black' },
backgroundAccentHover: { light: 'whitesmoke', dark: 'gray' },
backgroundAccentText: { light: 'black', dark: 'white' },
textAccent: { light: 'black', dark: 'white' },
}
}
})
You can force a specific color scheme:
export default defineConfig({
theme: {
colorScheme: 'dark' // or 'light'
}
})
Customize any CSS variable used in Vocs:
export default defineConfig({
theme: {
variables: {
color: {
background: {
light: 'white',
dark: 'black'
}
},
content: {
horizontalPadding: '40px',
verticalPadding: '80px'
}
}
}
})
Every element in Vocs can be customized via CSS classes using the .Vocs_{element}
pattern. For example:
.Vocs_H1 {
color: red;
}
Inspect your documentation's HTML to see available class names for customization.
You can set page-specific metadata in the frontmatter of Markdown pages using YAML format between ---
separators at the top of the page.
---
title: Example
description: This is an example page.
---
# Hello world
This is me.
- title (string): Page title for the
<title>
tag - description (string): Page description for meta tags
- date (string): Publication date
- authors (string[]): Page authors
- layout ("docs" | "landing" | "minimal"): Page layout type
docs
: Documentation page layout (default)landing
: Landing page layoutminimal
: Minimal layout without sidebar/header
- showSidebar (boolean): Toggle sidebar visibility
- showOutline (boolean | number): Toggle outline or specify depth
- showLogo (boolean): Toggle logo visibility in header
- showAiCta (boolean): Toggle AI call-to-action dropdown
---
content:
horizontalPadding: string
width: string
verticalPadding: string
---
Example with multiple options:
---
title: My Page
description: A comprehensive guide
authors:
- [jxom](https://x.com/jxom)
- [awkweb](https://x.com/awkweb)
date: 2023-12-01
layout: docs
showOutline: 2
content:
horizontalPadding: 40px
width: 100%
verticalPadding: 80px
---
Vocs supports dynamic open graph images that are displayed when sharing links on platforms like Twitter, Slack, or Telegram.
Use the built-in API by setting the ogImageUrl
in your config:
import { defineConfig } from 'vocs'
export default defineConfig({
ogImageUrl: 'https://vocs.dev/api/og?logo=%logo&title=%title&description=%description',
title: 'My Docs'
})
You can deploy your own OG Image API using Vercel Edge Functions:
- Clone and deploy the example repository
- Update your config with your deployed URL:
import { defineConfig } from 'vocs'
export default defineConfig({
ogImageUrl: 'https://<my-project>.vercel.app/api/og?logo=%logo&title=%title&description=%description',
title: 'My Docs'
})
Available template variables:
%logo
: Logo image URL%title
: Page title%description
: Page description
Configure different OG images for different paths:
import { defineConfig } from 'vocs'
export default defineConfig({
ogImageUrl: {
'/': 'https://vocs.dev/og-image.png',
'/docs': 'https://vocs.dev/api/og?logo=%logo&title=%title&description=%description',
},
title: 'My Docs'
})
Vocs provides two main navigation components: sidebar and top navigation.
Configure the sidebar in vocs.config.ts
:
import { defineConfig } from 'vocs'
export default defineConfig({
sidebar: [
{
text: 'Getting Started',
link: '/docs',
},
{
text: 'API',
collapsed: true,
items: [
{
text: 'Config',
link: '/docs/api/config',
},
],
}
]
})
Create different sidebars for different sections:
export default defineConfig({
sidebar: {
'/docs/': [
{
text: 'Getting Started',
link: '/docs',
},
// ... more items
],
'/examples/': [
{ text: 'React', link: '/examples/react' },
{ text: 'Vue', link: '/examples/vue' }
]
}
})
Configure the top navigation bar:
export default defineConfig({
topNav: [
{
text: 'Guide & API',
link: '/docs/getting-started',
match: '/docs'
},
{ text: 'Blog', link: '/blog' },
{
text: 'Version',
items: [
{
text: 'Changelog',
link: 'https://github.com/org/repo/changelog',
},
{
text: 'Contributing',
link: 'https://github.com/org/repo/contributing',
},
],
},
]
})
Top navigation items support:
text
: Display textlink
: Navigation URLmatch
: Path pattern for highlightingitems
: Dropdown menu items
Add custom CSS by creating a styles.css
file in the Vocs root directory:
my-project/
├── docs/
│ ├── pages/
│ │ ├── index.mdx
│ │ └── about.tsx
│ ├── public/
│ │ └── favicon.ico
│ └── styles.css
├── node_modules/
Example styles.css
:
body {
background-color: #f3f3f3;
}
.Vocs_H1 {
color: red;
}
// layout.tsx
import './global.css'
import './theme.css'
export default function Root({ children }) {
return children
}
import './theme.css'
# Hello world
This is me.
Vocs includes built-in Tailwind support. Enable it by importing in your styles.css
:
@import "tailwindcss";
TypeScript Twoslash is a markup language for JavaScript and TypeScript that enhances code samples with type information and compiler features.
Get type information about an identifier:
const example: string = "hello"
// ^?
Show auto-complete information:
type Example = { apple: 'foo' | 'bar' | 'baz' }
const example: Example = { apple: '|' }
// ^|
Highlight specific code ranges:
function add(foo: number, bar: number) {
// ^^^
return foo + bar
}
Remove code above the marker from output:
// Setup code
import { something } from 'somewhere'
// ---cut---
console.log(something)
Remove code after the marker:
console.log("This stays")
// ---cut-after---
console.log("This is removed")
Create multiple files in a single code block:
// @filename: types.d.ts
export type User = {
id: number
name: string
}
// @filename: index.ts
import { User } from './types'
const user: User = {
id: 1,
name: 'John'
}
Control TypeScript behavior with compiler flags:
// @strict: true
// @target: ES2020
// @lib: DOM,ES2020
Common flags include:
@noImplicitAny
@strictNullChecks
@allowJs
@checkJs
@jsx
@module
You can include other Markdown files in your documentation using MDX imports.
- Create a snippet file:
// snippet.mdx
### Hello world
This is my snippet.
- Import and use the snippet:
// example.mdx
import Snippet from './snippet.mdx'
# Example
This is an example of including a snippet.
<Snippet />
Since snippets are React components, you can pass props:
// example.mdx
import Snippet from './snippet.mdx'
<Snippet title="Hello world" content="This is my snippet." />
Access props in the snippet using the props
global variable:
// snippet.mdx
### {props.title}
{props.content}
Code Snippets in Vocs come in two forms:
- Virtual file snippets in your Markdown code
- Physical file snippets in your file system
To create a virtual file snippet:
- Define the snippet with a filename meta tag:
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
- Import the snippet using the
// [!include ...]
marker:
// [!include example.ts]
const blockNumber = await client.getBlockNumber()
For physical file snippets:
- Create a file in your codebase (e.g.,
docs/snippets/example.ts
):
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
- Import using the
// [!include ...]
marker with the file path:
// [!include ~/snippets/example.ts]
const blockNumber = await client.getBlockNumber()
You can include specific regions of code using // [!region]
and // [!endregion]
markers:
// [!region import]
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
// [!endregion import]
// [!region setup]
const client = createPublicClient({
chain: mainnet,
transport: http(),
})
// [!endregion setup]
Then import specific regions:
// [!include ~/snippets/example.ts:import]
// [!include ~/snippets/example.ts:setup]
For duplicate variable declarations in different regions, use the _$
suffix:
const block_$1 = await client.getBlock()
const block_$2 = await client.getBlock({ blockNumber: 42069n })
Use /(find)/(replace)/
syntax to modify imported snippets:
// [!include ~/snippets/example.ts /viem/@viem\/core/ /mainnet/sepolia/]
- Code Block Markers: You can include markers like line highlights in snippets:
const blockNumber = await client.getBlockNumber() // [!code hl]
- Twoslash Integration: Combine with Twoslash for type information:
const blockNumber = await client.getBlockNumber()
// ^?
- Twoslash with Virtual Files: Use multiple virtual files in Twoslash code blocks:
import { client } from './client.js'
const blockNumber = await client.getBlockNumber()
import { http, createPublicClient } from 'viem'
import { mainnet } from 'viem/chains'
export const client = createPublicClient({
chain: mainnet,
transport: http(),
})