Skip to main content
Version: 2.0.0-beta.14

Sidebar

Creating a sidebar is useful to:

  • Group multiple related documents
  • Display a sidebar on each of those documents
  • Provide a paginated navigation, with next/previous button

To use sidebars on your Docusaurus site:

  1. Define a file that exports a dictionary of sidebar objects.
  2. Pass this object into the @docusaurus/plugin-docs plugin directly or via @docusaurus/preset-classic.
docusaurus.config.js
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
sidebarPath: require.resolve('./sidebars.js'),
},
},
],
],
};

Default sidebar

If the sidebarPath is unspecified, Docusaurus automatically generates a sidebar for you, by using the filesystem structure of the docs folder:

sidebars.js
module.exports = {
mySidebar: [
{
type: 'autogenerated',
dirName: '.', // generate sidebar from the docs folder (or versioned_docs/<version>)
},
],
};

You can also define your sidebars explicitly.

A sidebar at its crux is a hierarchy of categories, doc links, and other hyperlinks.

type Sidebar =
// Normal syntax
| SidebarItem[]
// Shorthand syntax
| {[categoryLabel: string]: SidebarItem[]};

For example:

sidebars.js
module.exports = {
mySidebar: [
{
type: 'category',
label: 'Getting Started',
items: [
{
type: 'doc',
id: 'doc1',
},
],
},
{
type: 'category',
label: 'Docusaurus',
items: [
{
type: 'doc',
id: 'doc2',
},
{
type: 'doc',
id: 'doc3',
},
],
},
{
type: 'link',
label: 'Learn more',
href: 'https://example.com',
},
],
};

This is a sidebars file that exports one sidebar, called mySidebar. It has three top-level items: two categories and one external link. Within each category, there are a few doc links.

A sidebars file can contain multiple sidebar objects, identified by their object keys.

type SidebarsFile = {
[sidebarID: string]: Sidebar;
};

Using shorthands

You can express typical sidebar items without much customization more concisely with shorthand syntaxes. There are two parts to this: doc shorthand and category shorthand.

Doc shorthand

An item with type doc can be simply a string representing its ID:

// =================
// This item:
// =================
{
type: 'doc',
id: 'myDoc',
};
// =================
// Is equivalent to:
// =================
'myDoc';

So it's possible to simplify the example above to:

sidebars.js
module.exports = {
mySidebar: [
{
type: 'category',
label: 'Getting Started',
items: [
'doc1',
],
},
{
type: 'category',
label: 'Docusaurus',
items: [
'doc2',
'doc3',
],
},
{
type: 'link',
label: 'Learn more',
href: 'https://example.com',
},
],
};

Category shorthand

A category item can be represented by an object whose key is its label, and the value is an array of subitems.

// ===================
// This item:
// ===================
{
type: 'category',
label: 'Getting started',
items: ['doc1', 'doc2'],
};
// ===================
// Is equivalent to:
// ===================
{
'Getting started': ['doc1', 'doc2'],
};

This permits us to simplify that example to:

sidebars.js
module.exports = {
mySidebar: [
{
'Getting started': ['doc1'],
},
{
Docusaurus: ['doc2', 'doc3'],
},
{
type: 'link',
label: 'Learn more',
href: 'https://example.com',
},
],
};

Each shorthand object after this transformation will contain exactly one entry. Now consider the further simplified example below:

sidebars.js
module.exports = {
mySidebar: [
{
'Getting started': ['doc1'],
Docusaurus: ['doc2', 'doc3'],
},
{
type: 'link',
label: 'Learn more',
href: 'https://example.com',
},
],
};

Note how the two consecutive category shorthands are compressed into one object with two entries. This syntax generates a sidebar slice: you shouldn't see that object as one bulk item—this object is unwrapped, with each entry becoming a separate item, and they spliced together with the rest of the items (in this case, the "Learn more" link) to form the final sidebar level. Sidebar slices are also important when discussing autogenerated sidebars.

Understanding sidebar items

We have introduced three types of item types in the above example: doc, category, and link, whose usage are fairly intuitive. We will formally introduce their APIs. There's also a fourth type: autogenerated, which we will explain in detail later.

  • Doc: link to a doc page, associating it with the sidebar
  • Link: link to any internal or external page
  • Category: creates a dropdown of sidebar items
  • Autogenerated: generate a sidebar slice automatically
  • *Ref: link to a doc page, without associating it with the sidebar

Use the doc type to link to a doc page and assign that doc to a sidebar:

type SidebarItemDoc =
// Normal syntax
| {
type: 'doc';
id: string;
label: string; // Sidebar label text
className?: string; // Class name for sidebar label
}

// Shorthand syntax
| string; // docId shortcut

Example:

sidebars.js
module.exports = {
mySidebar: [
// Normal syntax:
{
type: 'doc',
id: 'doc1', // document id
label: 'Getting started', // sidebar label
},

// Shorthand syntax:
'doc2', // document id
],
};

If you use the doc shorthand or autogenerated sidebar, you would lose the ability to customize the sidebar label through item definition. You can, however, use the sidebar_label markdown front matter within that doc, which has a higher precedence over the label key in the sidebar item.

note

A doc item sets an implicit sidebar association. Don't assign the same doc to multiple sidebars: change the type to ref instead.

Use the link type to link to any page (internal or external) that is not a doc.

type SidebarItemLink = {
type: 'link';
label: string;
href: string;
className?: string;
};

Example:

sidebars.js
module.exports = {
myLinksSidebar: [
// External link
{
type: 'link',
label: 'Facebook', // The link label
href: 'https://facebook.com', // The external URL
},

// Internal link
{
type: 'link',
label: 'Home', // The link label
href: '/', // The internal path
},
],
};

Use the category type to create a hierarchy of sidebar items.

type SidebarItemCategory = {
type: 'category';
label: string; // Sidebar label text.
items: SidebarItem[]; // Array of sidebar items.
className?: string;

// Category options:
collapsible: boolean; // Set the category to be collapsible
collapsed: boolean; // Set the category to be initially collapsed or open by default
link: SidebarItemCategoryLinkDoc | SidebarItemCategoryLinkGeneratedIndex;
};

Example:

sidebars.js
module.exports = {
docs: [
{
type: 'category',
label: 'Guides',
collapsible: true,
collapsed: false,
items: [
'creating-pages',
{
type: 'category',
label: 'Docs',
items: ['introduction', 'sidebar', 'markdown-features', 'versioning'],
},
],
},
],
};
tip

Use the shorthand syntax when you don't need customizations:

sidebars.js
module.exports = {
docs: {
Guides: [
'creating-pages',
{
Docs: ['introduction', 'sidebar', 'markdown-features', 'versioning'],
},
],
},
};

With category links, clicking on a category can navigate you to another page.

tip

Use category links to introduce a category of documents.

A category can link to an existing document.

sidebars.js
module.exports = {
docs: [
{
type: 'category',
label: 'Guides',
link: {type: 'doc', id: 'introduction'},
items: ['pages', 'docs', 'blog', 'search'],
},
],
};

See it in action in the i18n introduction page.

Generated index page

You can auto-generate an index page that displays all the direct children of this category. The slug allows you to customize the generated page's route, which defaults to /category/[categoryName].

sidebars.js
module.exports = {
docs: [
{
type: 'category',
label: 'Guides',
link: {
type: 'generated-index',
title: 'Docusaurus Guides',
description: 'Learn about the most important Docusaurus concepts!',
slug: '/category/docusaurus-guides',
},
items: ['pages', 'docs', 'blog', 'search'],
},
],
};

See it in action in the Docusaurus Guides pages.

tip

Use generated-index links as a quick way to get an introductory document.

Collapsible categories

We support the option to expand/collapse categories. Categories are collapsible by default, but you can disable collapsing with collapsible: false.

sidebars.js
module.exports = {
docs: [
{
type: 'category',
label: 'Guides',
items: [
'creating-pages',
{
type: 'category',
collapsible: false,
label: 'Docs',
items: ['introduction', 'sidebar', 'markdown-features', 'versioning'],
},
],
},
],
};

To make all categories non-collapsible by default, set the sidebarCollapsible option in plugin-content-docs to false:

docusaurus.config.js
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
sidebarCollapsible: false,
},
},
],
],
};
note

The option in sidebars.js takes precedence over plugin configuration, so it is possible to make certain categories collapsible when sidebarCollapsible is set to false globally.

Expanded categories by default

Collapsible categories are collapsed by default. If you want them to be expanded on first render, you can set collapsed to false:

sidebars.js
module.exports = {
docs: {
Guides: [
'creating-pages',
{
type: 'category',
label: 'Docs',
collapsed: false,
items: ['markdown-features', 'sidebar', 'versioning'],
},
],
},
};

Similar to collapsible, you can also set the global configuration options.sidebarCollapsed to false. Individual collapsed options in sidebars.js will still take precedence over this configuration.

docusaurus.config.js
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
sidebarCollapsed: false,
},
},
],
],
};
caution

When a category has collapsed: true but collapsible: false (either through sidebars.js or through plugin configuration), the latter takes precedence and the category is still rendered as expanded.

Docusaurus can create a sidebar automatically from your filesystem structure: each folder creates a sidebar category, and each file creates a doc link.

type SidebarItemAutogenerated = {
type: 'autogenerated';
dirName: string; // Source folder to generate the sidebar slice from (relative to docs)
};

Docusaurus can generate a full sidebar from your docs folder:

sidebars.js
module.exports = {
myAutogeneratedSidebar: [
{
type: 'autogenerated',
dirName: '.', // '.' means the current docs folder
},
],
};

An autogenerated item is converted by Docusaurus to a sidebar slice (also discussed in category shorthands): a list of items of type doc or category, so you can splice multiple autogenerated items from multiple directories, interleaving them with regular sidebar items, in one sidebar level.

A real world example
Consider this file structure:
docs
├── api
│ ├── product1-api
│ │ └── api.md
│ └── product2-api
│ ├── basic-api.md
│ └── pro-api.md
├── intro.md
└── tutorials
├── advanced
│ ├── advanced1.md
│ ├── advanced2.md
│ └── read-more
│ ├── resource1.md
│ └── resource2.md
├── easy
│ ├── easy1.md
│ └── easy2.md
├── tutorial-end.md
├── tutorial-intro.md
└── tutorial-medium.md

And assume every doc's ID is just its file name. If you define an autogenerated sidebar like this:

sidebars.js
module.exports = {
mySidebar: [
'intro',
{
type: 'category',
label: 'Tutorials',
items: [
'tutorial-intro',
{
type: 'autogenerated',
dirName: 'tutorials/easy', // Generate sidebar slice from docs/tutorials/easy
},
'tutorial-medium',
{
type: 'autogenerated',
dirName: 'tutorials/advanced', // Generate sidebar slice from docs/tutorials/hard
},
'tutorial-end',
],
},
{
type: 'autogenerated',
dirName: 'api', // Generate sidebar slice from docs/api
},
{
type: 'category',
label: 'Community',
items: ['team', 'chat'],
},
],
};

It would be resolved as:

sidebars.js
module.exports = {
mySidebar: [
'intro',
{
type: 'category',
label: 'Tutorials',
items: [
'tutorial-intro',
// Two files in docs/tutorials/easy
'easy1',
'easy2',
'tutorial-medium',
// Two files and a folder in docs/tutorials/hard
'advanced1',
'advanced2',
{
type: 'category',
label: 'read-more',
items: ['resource1', 'resource2'],
},
'tutorial-end',
],
},
// Two folders in docs/api
{
type: 'category',
label: 'product1-api',
items: ['api'],
},
{
type: 'category',
label: 'product2-api',
items: ['basic-api', 'pro-api'],
},
{
type: 'category',
label: 'Community',
items: ['team', 'chat'],
},
],
};

Note how the autogenerate source directories themselves don't become categories: only the items they contain do. This is what we mean by "sidebar slice".

Category index convention

Docusaurus can automatically link a category to its index document.

A category index document is a document following one of those filename conventions:

  • Named as index (case-insensitive): docs/Guides/index.md
  • Named as README (case-insensitive): docs/Guides/README.mdx
  • Same name as parent folder: docs/Guides/Guides.md

This is equivalent to using a category with a doc link:

sidebars.js
module.exports = {
docs: [
{
type: 'category',
label: 'Guides',
link: {type: 'doc', id: 'Guides/index'},
items: [],
},
],
};
tip

Naming your introductory document README.md makes it show up when browsing the folder using the GitHub interface, while using index.md makes the behavior more in line with how HTML files are served.

Autogenerated sidebar metadata

For hand-written sidebar definitions, you would provide metadata to sidebar items through sidebars.js; for autogenerated, Docusaurus would read them from the item's respective file. In addition, you may want to adjust the relative position of each item, because by default, items within a sidebar slice will be generated in alphabetical order (using files and folders names).

For docs: use additional front matter. The label and className attributes now become sidebar_label and sidebar_class_name, while there's an additional sidebar_position front matter.

docs/tutorials/tutorial-easy.md
---
sidebar_position: 2
sidebar_label: Easy
sidebar_class_name: green
---
# Easy Tutorial

This is the easy tutorial!

For categories: add a _category_.json or _category_.yml file in the respective folder. You can specify any category metadata and also the position metadata.

docs/tutorials/_category_.json
{
"position": 2.5,
"label": "Tutorial",
"collapsible": true,
"collapsed": false,
"className": "red",
"link": {
"type": "generated-index",
"title": "Tutorial overview"
}
}
info

If the link is explicitly specified, Docusaurus will not apply any default conventions.

The doc links can be specified relatively, e.g. if the category is generated with the guides directory, "link": {"type": "doc", "id": "intro"} will be resolved to the ID guides/intro, only falling back to intro if a doc with the former ID doesn't exist.

info

The position metadata is only used within a sidebar slice: Docusaurus does not re-order other items of your sidebar.

Using number prefixes

A simple way to order an autogenerated sidebar is to prefix docs and folders by number prefixes, which also makes them appear in the file system in the same order when sorted by file name:

docs
├── 01-Intro.md
├── 02-Tutorial Easy
│ ├── 01-First Part.md
│ ├── 02-Second Part.md
│ └── 03-End.md
├── 03-Tutorial Hard
│ ├── 01-First Part.md
│ ├── 02-Second Part.md
│ ├── 03-Third Part.md
│ └── 04-End.md
└── 04-End.md

To make it easier to adopt, Docusaurus supports multiple number prefix patterns.

By default, Docusaurus will remove the number prefix from the doc id, title, label and URL paths.

caution

Prefer using additional metadata.

Updating a number prefix can be annoying, as it can require updating multiple existing markdown links:

docs/02-Tutorial Easy/01-First Part.md
- Check the [Tutorial End](../04-End.md);
+ Check the [Tutorial End](../05-End.md);

Customize the sidebar items generator

You can provide a custom sidebarItemsGenerator function in the docs plugin (or preset) config:

docusaurus.config.js
module.exports = {
plugins: [
[
'@docusaurus/plugin-content-docs',
{
async sidebarItemsGenerator({
defaultSidebarItemsGenerator,
numberPrefixParser,
item,
version,
docs,
}) {
// Example: return an hardcoded list of static sidebar items
return [
{type: 'doc', id: 'doc1'},
{type: 'doc', id: 'doc2'},
];
},
},
],
],
};
tip

Re-use and enhance the default generator instead of writing a generator from scratch: the default generator we provide is 250 lines long.

Add, update, filter, re-order the sidebar items according to your use-case:

docusaurus.config.js
// Reverse the sidebar items ordering (including nested category items)
function reverseSidebarItems(items) {
// Reverse items in categories
const result = items.map((item) => {
if (item.type === 'category') {
return {...item, items: reverseSidebarItems(item.items)};
}
return item;
});
// Reverse items at current level
result.reverse();
return result;
}

module.exports = {
plugins: [
[
'@docusaurus/plugin-content-docs',
{
async sidebarItemsGenerator({defaultSidebarItemsGenerator, ...args}) {
const sidebarItems = await defaultSidebarItemsGenerator(args);
return reverseSidebarItems(sidebarItems);
},
},
],
],
};

Hideable sidebar

By enabling the themeConfig.hideableSidebar option, you can make the entire sidebar hideable, allowing users to better focus on the content. This is especially useful when content is consumed on medium-sized screens (e.g. tablets).

docusaurus.config.js
module.exports = {
themeConfig: {
hideableSidebar: true,
},
};

Using multiple sidebars

You can create a sidebar for each set of Markdown files that you want to group together.

tip

The Docusaurus site is a good example of using multiple sidebars:

Consider this example:

sidebars.js
module.exports = {
tutorialSidebar: {
'Category A': ['doc1', 'doc2'],
},
apiSidebar: ['doc3', 'doc4'],
};

When browsing doc1 or doc2, the tutorialSidebar will be displayed; when browsing doc3 or doc4, the apiSidebar will be displayed.

Following the example above, if a commonDoc is included in both sidebars:

sidebars.js
module.exports = {
tutorialSidebar: {
'Category A': ['doc1', 'doc2', 'commonDoc'],
},
apiSidebar: ['doc3', 'doc4', 'commonDoc'],
};

How does Docusaurus know which sidebar to display when browsing commonDoc? Answer: it doesn't, and we don't guarantee which sidebar it will pick. In this case, in order to remove the ambiguity, you can use the special ref sidebar item type.

The ref type is identical to the doc type in every way, except that it doesn't set the association. It only registers itself as a link, but doesn't take part in generating navigation metadata. When generating pagination and displaying sidebar, ref items are completely ignored.

So you can turn the sidebars above into:

sidebars.js
module.exports = {
tutorialSidebar: {
'Category A': [
'doc1',
'doc2',
{type: 'ref', id: 'commonDoc'},
],
},
apiSidebar: ['doc3', 'doc4', 'commonDoc'],
};

Now, although the link to commonDoc is still included in the tutorialSidebar sidebar, when browsing commonDoc, only apiSidebar can be possibly displayed.

Generating pagination

Docusaurus uses the sidebar to generate the "next" and "previous" pagination links at the bottom of each doc page. It strictly uses the sidebar that is displayed: if no sidebar is associated, no pagination is generated either.

You can customize pagination with front matter pagination_next and pagination_prev. Consider this sidebar:

sidebars.js
module.exports = {
tutorial: [
'introduction',
{
installation: ['windows', 'linux', 'macos'],
},
'getting-started',
],
};

The pagination next link on "windows" points to "linux", but that doesn't make sense: you would want readers to proceed to "getting started" after installation. In this case, you can set the pagination manually:

windows.md
---
pagination_next: getting-started
---
# Installation on Windows

You can also disable displaying a pagination link with pagination_next: null or pagination_prev: null.

The pagination label by default is the sidebar label. You can use the front matter pagination_label to customize how this doc appears in the pagination.

Passing custom props

To pass in custom props to a swizzled sidebar item, add the optional customProps object to any of the items:

{
type: 'doc',
id: 'doc1',
customProps: {
/* props */
},
};

Complex sidebars example

Real-world example from the Docusaurus site:

sidebars.js
const sidebars = {
docs: [
'introduction',
{
type: 'category',
label: 'Getting Started',
link: {
type: 'generated-index',
},
collapsed: false,
items: [
'installation',
'configuration',
'playground',
'typescript-support',
],
},
{
type: 'category',
label: 'Guides',
link: {
type: 'generated-index',
title: 'Docusaurus Guides',
description:
"Let's learn about the most important Docusaurus concepts!",
keywords: ['guides'],
image: '/img/docusaurus.png',
},
items: [
'guides/creating-pages',
{
type: 'category',
label: 'Docs',
link: {
type: 'doc',
id: 'guides/docs/introduction',
},
items: [
'guides/docs/create-doc',
{
type: 'category',
label: 'Sidebar',
link: {
type: 'doc',
id: 'guides/docs/sidebar/index',
},
items: [
'guides/docs/sidebar/items',
'guides/docs/sidebar/autogenerated',
'guides/docs/sidebar/multiple-sidebars',
],
},
'guides/docs/versioning',
'guides/docs/markdown-features',
'guides/docs/multi-instance',
],
},
'blog',
{
type: 'category',
label: 'Markdown Features',
link: {
type: 'doc',
id: 'guides/markdown-features/introduction',
},
items: [
'guides/markdown-features/react',
'guides/markdown-features/tabs',
'guides/markdown-features/code-blocks',
'guides/markdown-features/admonitions',
'guides/markdown-features/headings',
'guides/markdown-features/inline-toc',
'guides/markdown-features/assets',
'guides/markdown-features/plugins',
'guides/markdown-features/math-equations',
'guides/markdown-features/head-metadata',
],
},
'styling-layout',
'static-assets',
'search',
'browser-support',
'seo',
'deployment',
{
type: 'category',
label: 'Internationalization',
link: {type: 'doc', id: 'i18n/introduction'},
items: [
{
type: 'doc',
id: 'i18n/tutorial',
label: 'Tutorial',
},
{
type: 'doc',
id: 'i18n/git',
label: 'Using Git',
},
{
type: 'doc',
id: 'i18n/crowdin',
label: 'Using Crowdin',
},
],
},
],
},
{
type: 'category',
label: 'Advanced Guides',
items: ['using-plugins', 'using-themes', 'presets'],
},
{
type: 'category',
label: 'Migrating from v1 to v2',
items: [
'migration/migration-overview',
'migration/migration-automated',
'migration/migration-manual',
'migration/migration-versioned-sites',
'migration/migration-translated-sites',
],
},
],
api: [
'cli',
'docusaurus-core',
{
type: 'autogenerated',
dirName: 'api',
},
],
};
module.exports = sidebars;