Not only has Bootstrap helped millions of developers build websites, but their documentation is built using Hugo. Let's dive in and deconstruct the Bootstrap documentation.
Bootstrap is used to rapidly develop consistent, responsive websites. It was initially created at Twitter as a way to encourage design consistency in internal tools. Later it was publicly released in August 2011 and has become one of the most popular projects on GitHub.
The most important part of a documentation site is the content so let’s start there. The front matter for content pages is simple, using five variables for the most part:
description are self-explanatory. Things get interesting with
toc, which are used to build navigation menus. We’ll look at how navigation works in the next section. For the body content, Bootstrap does a great job of using simple markdown. The content is a mix of headings, paragraphs, code blocks, lists, links, and the occasional HTML block for tables and accessibility.
Keeping the markdown simple is excellent because it makes it easier for the core team to maintain their documentation and for others to contribute. It also helps keep consistency throughout the site.
The Bootstrap documentation has three levels of navigation:
This is the primary navigation for the Bootstrap site and also the most simple in terms of implementation. Each link is hard coded and has an if statement to trigger the active state:
The sidebar is more tricky. It’s a two-level navigation component used on documentation pages. The first level is the group title, a high-level concept with an arrow indicating it can be expanded. Clicking on the group title expands the sidebar to show the navigation items related to the group. The sidebar is populated from a YAML data file:
Using a data file here makes sense for a couple of reasons:
$group_slug is calculated by slugifying the title in the data file.
$group_slug is then compared to the
group front matter field (The one we saw in the content section ) on the current page being rendered. If they match, then the current page is part of this navigation group. This state is stored in the
$is_active_group variable. The next code block renders the group title. The interesting part from a Jamstack perspective is seeing how they use
$is_active_group. It’s used to add a collapsed class if it’s not the active group, it’s also used to set two accessibility attributes:
Following the group title, we have the logic to render the navigation items. First, the pages in the current group are iterated over. Each page is assigned to
$doc’s title is slugified and checked to see if it’s the current page in a similar way to how the active group was calculated. The result of this is assigned to
$href is a combination of the
$doc_slug. It’s a bit magic because there just happens to be a page with that URL. There’s no real connection there from Hugo’s point of view. This will work as long the team is consistent with their structure and doesn’t override any permalinks. As an improvement, you could find the source page using the
$doc_slug and get the permalink from there. This would be less fragile as you are free to change the permalink. However, it would add extra code and complexity, so it may not be necessary here.
One point worth noting is while it looks easy to update a navigation group or item title in the YAML file, there’s more than meets the eye. The titles have
urlize run on them to link them back to the original document as we saw. If you want to update a title for the navigation, you will also have to change the file name of the source file. Otherwise the link will break. As a small improvement, I would opt to have the slugified references in the YAML file and then have an optional front matter field in each document called
menu_title if you want to use something other than
title for menu items.
On the right side of the most of their documentation pages, Bootstrap includes a table of contents which lists the headings on the page. It’s a nice way to help users find the content they’re looking for. Hugo makes generating a table of contents super straight forward, it parses the markdown and automatically makes the HTML output available with the variable
.TableOfContents. As we saw before, some pages have a
toc front matter variable. The Bootstrap site uses this variable to determine if the table of contents should be rendered:
Successful software frameworks like Bootstrap release many major versions of their software. Each major version likely differs enough from each other to warrant its own documentation. Bootstrap has a clever dropdown that makes it easy to switch between versions.
This file is iterated over on the versions page to create the version appendix. Each major and minor version of Bootstrap has its own branch (or tag), which contains only that version’s documentation. The URL structure has a segment for the version number e.g.
/docs/5.0/getting-started/introduction/. I don’t have visibility into how this is deployed but what I suspect is that each site is generated independently, and then combined after the build. CloudCannon has a feature called subpaths that makes it easy to do something similar - mount multiple sites together to look like a single site.
I’m a big fan of this strategy for documentation versioning for several reasons:
Search is a great way to help users quickly find what they’re looking for. There’s several ways to add search to a static site. Bootstrap uses Algolia, which is hard to beat when it comes to ease of integration and search performance.
Algolia has a free tool built explicitly for documentation called Docsearch. The way it works is simple:
Bootstrap is a fantastic example of a well-built documentation site on Hugo. If you’re building a documentation site, I’d recommend having a dig around their source code as they typically have elegant solutions to common problems.