Introduction
Hugo Book is a documentation theme for Hugo. It provides a clean, readable layout for technical docs with minimal dependencies and no build tooling beyond Hugo itself.
Design Goals
- Minimalism over features.
- The theme ships only what most documentation sites need: a sidebar menu, search, and a few shortcodes. There is no attempt to cover every use case. CSS is written by hand, not generated by a framework. JavaScript is optional for core navigation.
- Theme as an extendable base.
- Hugo Book is meant to be extended and adapted. ‘Inject’ partials, custom CSS, and Hugo’s template override system let you change any part of the theme without modifying the source, while keeping the codebase intentionally small.
- Long-term maintainability.
- Few dependencies means fewer things to break. The theme avoids heavy JavaScript libraries, CSS frameworks, and complex build pipelines.
Links
Create a Site
Prerequisites
Quick Start
Use the starter repository to get a working site in seconds. It can also be used as a GitHub template to create a new repository.
git clone https://github.com/alex-shpak/hugo-book-starter documentation
cd documentation
git submodule update --init --remote
hugo server --minifyBy default, the theme renders pages under docs/ section as the sidebar menu. See Content Organisation for details.
Installation Methods
The simplest approach. The theme is vendored directly into your repository.
git init
git submodule add https://github.com/alex-shpak/hugo-book themes/hugo-bookSet the theme in your config
hugo.tomltheme = 'hugo-book'To update the theme later
git submodule update --remote --mergeUses Hugo Modules (requires Go).
Initialize your site as a module
hugo mod init github.com/user/my-docsAdd the theme import to your config
hugo.toml[module]
[[module.imports]]
path = 'github.com/alex-shpak/hugo-book'To update the theme later
hugo mod get -uDownload the theme from GitHub releases and extract it to themes/hugo-book.
Set the theme in your config
hugo.tomltheme = 'hugo-book'To update, download and extract the new release again.
Minimal Configuration
hugo.tomlbaseURL = 'https://example.com/'
title = 'My Documentation'
theme = 'hugo-book'
# Required for mermaid and katex shortcodes
[markup.goldmark.renderer]
unsafe = trueSee Configuration for the full list of parameters.
Configuration
All theme parameters are set under [params] in your site config. Every parameter is optional.
Theme Parameters
hugo.toml[params]
# Color theme: 'light', 'dark' or 'auto'
# Auto switches based on OS/browser preference
BookTheme = 'light'
# Show table of contents on right side of pages
# Can also be set per-page via frontmatter
BookToC = true
# Path to favicon file relative to 'static' directory
BookFavicon = 'favicon.png'
# Path to logo image file relative to 'static' directory
BookLogo = 'logo.png'
# Root section to render as sidebar menu
# Default: 'docs'
BookSection = 'docs'
# Repository URL, used for edit and commit links
BookRepo = 'https://github.com/user/repo'
# Template for "Last Modified" commit link in page footer
# Requires enableGitInfo = true in site config
# Available context: .Site, .Page, .GitInfo
BookLastChangeLink = '{{ .Site.Params.BookRepo }}/commit/{{ .GitInfo.Hash }}'
# Template for "Edit this page" link in page footer
# Available context: .Site, .Page, .Path
BookEditLink = '{{ .Site.Params.BookRepo }}/edit/main/{{ .Path }}'
# Date format used in git info and blog posts
BookDateFormat = 'January 2, 2006'
# Enable full-text search with MiniSearch
BookSearch = true
# Enable comments template on pages
# By default uses Disqus; override partials/docs/comments.html for others
BookComments = true
# /!\ Experimental, may change or be removed.
# Enable portable markdown links to resolve relative .md links to Hugo URLs.
# Lets you write [text](./other.md) instead of Hugo's relref shortcode.
# false - disabled, relative .md links not resolved
# 'warning' - enabled, prints a build warning if linked page doesn't exist
# 'error' - enabled, fails the build if linked page doesn't exist
BookPortableLinks = false
# /!\ Experimental, may change or be removed.
# Register a service worker for offline access to visited pages.
# false - disabled (default)
# true - caches pages as you visit them
# 'precache' - pre-populates cache with all site pages on first load
BookServiceWorker = false
# Only show languages that have translations for current page
BookTranslatedOnly = falseSearch
Full-text search is enabled by default using MiniSearch. The search index is built at page load from a generated JSON file.
hugo.toml[params]
BookSearch = trueTo exclude a page from the search index, set bookSearchExclude: true in its frontmatter.
If search is not working, verify that baseURL in your config matches the URL where the site is hosted. A mismatch prevents the search index from loading.
Hugo Site Configuration
These Hugo settings are relevant for the theme
hugo.toml# Preserve URL casing (recommended)
disablePathToLower = true
# Enable git metadata for "Last Modified" footer
enableGitInfo = trueMarkup
Goldmark Renderer
The unsafe option is required for Mermaid and KaTeX shortcodes to render correctly
hugo.toml[markup.goldmark.renderer]
unsafe = trueTable of Contents
Control the heading levels included in the table of contents
hugo.toml[markup.tableOfContents]
startLevel = 1
endLevel = 4The startLevel and endLevel values apply globally. Individual pages can toggle the ToC on or off with the bookToC frontmatter parameter.
Output Formats
The theme supports plain text output alongside HTML, useful for accessibility and LLMs
hugo.toml[outputFormats.txt]
mediaType = 'text/plain'
baseName = 'source'
isPlainText = true
[outputs]
home = ['html', 'txt', 'rss']
page = ['html', 'txt']
section = ['html', 'txt']Content Organisation
Hugo Book renders pages from a section as a sidebar menu. By default this is the docs/ directory.
Example Directory Structure
content/
├── docs/
│ ├── _index.md
│ ├── getting-started.md
│ ├── guide/
│ │ ├── _index.md
│ │ ├── install.md
│ │ └── configure.md
│ └── reference/
│ └── _index.md
├── posts/
│ ├── _index.md
│ └── my-post.md
└── _index.mdPages are ordered by weight frontmatter, then alphabetically. Section _index.md files define the section entry in the menu.
Changing the Menu Section
By default, pages under docs/ are rendered as the sidebar menu. Change this with the BookSection parameter in Configuration. Set to '/' to render all top-level sections.
Page Layouts
The theme provides several layouts:
| Layout | Usage | Description |
|---|---|---|
| (default) | Documentation pages | Sidebar menu + content + optional ToC |
landing | layout: landing | Full-width, no sidebar. Used for homepages. |
book | layout: book | Single-page view with all subsections listed |
posts | Pages under posts/ | Blog-style with date, tags, pagination |
Set the layout in frontmatter
_index.md---
layout: landing
---See Pages for frontmatter reference and Menus for navigation controls.
Page Frontmatter
Every page can use these frontmatter parameters to control its behavior in the theme.
---
title: My Page
weight: 10
bookToC: true
bookCollapseSection: true
---+++
title = 'My Page'
weight = 10
bookToC = true
bookCollapseSection = true
+++{
"title": "My Page",
"weight": 10,
"bookToC": true,
"bookCollapseSection": true
}Navigation
These parameters control how the page appears in the sidebar menu. Set in page frontmatter.
| Parameter | Default | Description |
|---|---|---|
weight | Menu ordering. Lower values appear first. Without weight, pages are sorted alphabetically. | |
bookHidden | false | Hide the page from the sidebar menu. The page is still accessible by URL. |
bookCollapseSection | false | Make a section collapsible in the sidebar. Subsections are hidden until clicked. |
bookFlatSection | false | Display subsection pages at the same level instead of nesting them. |
bookHref | Override the menu link with an external URL. | |
bookIcon | Display an icon next to the menu entry. |
Content Display
These parameters control page content rendering. Set in page frontmatter.
| Parameter | Default | Description |
|---|---|---|
bookToC | Show or hide the table of contents. Overrides the site-level BookToC setting. | |
bookComments | Show or hide comments. Overrides the site-level BookComments setting. | |
bookSearchExclude | false | Exclude this page from the search index. |
See Blog for post-specific frontmatter.
Blog
Hugo Book includes templates for blog-style posts with dates, tags, and pagination. Blog functionality is very basic.
Setup
Create a posts/ section in your content directory
content/
└── posts/
├── _index.md
└── my-first-post.mdAdd the blog section to a menu so readers can find it
---
title: Blog
menu:
after:
weight: 5
---Post Frontmatter
---
title: "My First Post"
date: 2025-01-15
tags: ["hugo", "documentation"]
categories: ["Guides"]
---Thumbnails
Posts can display a thumbnail image. By default the theme looks for a file matching thumbnail.* in the post’s page bundle. Override the pattern per-post
---
bookPostThumbnail: "cover.*"
---Date Format
The date display format is configured site-wide via BookDateFormat. See Configuration for details.
Multi-Language Support
Hugo Book supports Hugo’s multilingual mode with content translation by directory.
Configuration
Define languages in your site config
hugo.toml[languages]
[languages.en]
label = 'English'
contentDir = 'content.en'
weight = 1
[languages.zh]
label = 'Chinese'
contentDir = 'content.zh'
weight = 2
[languages.he]
label = 'Hebrew'
contentDir = 'content.he'
direction = 'rtl'
weight = 3A language selector dropdown appears automatically when multiple languages are configured.
RTL Support
Set direction = 'rtl' on a language to enable right-to-left layout. The entire page layout, including the sidebar menu, mirrors automatically.
Translation Dropdown
By default, all configured languages appear in the selector. To only show languages that have a translation for the current page
hugo.toml[params]
BookTranslatedOnly = trueShortcodes
Hugo Book includes shortcodes for common documentation patterns. All interactive shortcodes work without JavaScript using CSS-only techniques.
Hugo shortcodes use two delimiter styles:
{{< shortcode >}}- Renders inner content as plain HTML. Use for shortcodes that don’t contain markdown.
{{% shortcode %}}- Processes inner content as markdown. Use when the shortcode body contains markdown formatting.
Use
{{% shortcode %}}when the body contains markdown that needs to be rendered.{{< shortcode >}}passes content as-is without markdown processing. When nesting shortcodes (e.g. tabs inside columns), the outer shortcode must use{{% shortcode %}}for the inner shortcodes and markdown to be processed.
Asciinema
Embed terminal recordings with the Asciinema player.
Syntax
{{< asciinema
cast="recording.cast"
loop=true
autoplay=true
speed=2 >}}The cast parameter accepts page resources, site resources, or remote URLs.
Example
Parameters
cast- Path to the
.castfile. Can be a local resource or a remote URL.
All other parameters are passed directly to the Asciinema player. See the Asciinema player options for the full list.
Common options: autoplay, loop, speed, theme, cols, rows, idleTimeLimit, preload.
Columns
Organize content horizontally. Renders a markdown list as up to 3 side-by-side columns.
Syntax
{{% columns [ratio="1:1"] [class="..."] %}}
- ### Left
Content...
- ### Right
Content...
{{% /columns %}}Example
File-Tree Menu
The sidebar menu is automatically generated from your content directory structure. Pages are ordered by
weightfrontmatter.Hugo Menus
Additional menu entries can be added above or below the file-tree using Hugo’s standard menu system in your site config.
Landing Menu
Pages with
layout: landinguse a separate menu defined undermenu.homefor header navigation.
Custom Ratio
Set relative column widths with the ratio parameter
{{% columns ratio="1:2" %}}
- ### Sidebar
- ### Content Area
{{% /columns %}}Details
Collapsible content using the HTML5 <details> element.
Syntax
Positional arguments:
{{% details "Title" [open] %}}
Markdown content
{{% /details %}}Named parameters:
{{% details title="Title" open=true %}}
Markdown content
{{% /details %}}Example
What Hugo version is required?
Hugo Book requires Hugo {x} or later.
How do I override the theme?
Create matching files in your project’s layouts/ or assets/ directory. Hugo’s lookup order will use your files over the theme’s.
Parameters
title(or first positional argument)- The summary text shown when collapsed.
open(or second positional argument)- Start expanded. Default: collapsed.
Images
Enhanced image display with click-to-expand behavior.
Syntax
{{< image src="photo.jpg" alt="Description" title="Caption" loading="lazy" >}}Example
Parameters
src- Path to the image. Supports page resources, site resources, and URLs.
alt- Alternate text for accessibility.
title- Caption displayed below the image.
loading- Loading strategy:
lazy,eager, orauto. class- Additional CSS classes on the
<img>element.
OpenAPI
Renders an OpenAPI 3.x specification as a documentation page. Operations are grouped by their first tag.
Syntax
{{% openapi src="spec.json" %}}The spec file is loaded via resources.Get, so the path is relative to the site’s assets/ directory. JSON and YAML are both supported.
Example
This API allows writing down marks on a Tic Tac Toe board and requesting the state of the board or of individual squares.
v1.0.0
Security
app2AppOauthoauth2- Basic HTTP Authentication
basicHttpAuthenticationhttpBasic- Bearer token using a JWT
bearerHttpAuthenticationhttpBearerJWT- API key provided in console
defaultApiKeyapiKeyinheader(api-key)user2AppOauthoauth2
Gameplay
Get the whole board
Retrieves the current state of the board and the winner.
Request (requires defaultApiKey, app2AppOauth)
GET /boardResponses
200: OK
Schema: status
| Property | Type | Required | Description |
|---|---|---|---|
board | board | no | |
winner | winner | no | Winner of the game. . means nobody has won yet. |
Get a single board square
Retrieves the requested square.
Request (requires bearerHttpAuthentication, user2AppOauth)
GET /board/{row}/{column}Path parameters
| Parameter name | Value | Description | Additional |
|---|---|---|---|
row | coordinate | Board row (vertical coordinate) | Required, Example: 1 |
column | coordinate | Board column (horizontal coordinate) | Required, Example: 1 |
Responses
200: OK
Schema: mark
400: The provided parameters are incorrect
text/html"Illegal coordinates"Schema: errorMessage
Set a single board square
Places a mark on the board and retrieves the whole board and the winner (if any).
Request (requires bearerHttpAuthentication, user2AppOauth)
PUT /board/{row}/{column}Path parameters
| Parameter name | Value | Description | Additional |
|---|---|---|---|
row | coordinate | Board row (vertical coordinate) | Required, Example: 1 |
column | coordinate | Board column (horizontal coordinate) | Required, Example: 1 |
Request body (required)
Schema: mark
Responses
200: OK
Schema: status
| Property | Type | Required | Description |
|---|---|---|---|
board | board | no | |
winner | winner | no | Winner of the game. . means nobody has won yet. |
400: The provided parameters are incorrect
illegalCoordinates
text/html"Illegal coordinates."invalidMark
text/html"Invalid Mark (X or O)."notEmpty
text/html"Square is not empty."Schema: errorMessage
Models
board
Type: array of array of mark
coordinate
Type: integer
errorMessage
A text message describing an error
Type: string
mark
Possible values for a board square. . means empty square.
Type: string (enum: ., X, O)
status
| Property | Type | Required | Description |
|---|---|---|---|
board | board | no | |
winner | winner | no | Winner of the game. . means nobody has won yet. |
winner
Winner of the game. . means nobody has won yet.
Type: string (enum: ., X, O)
Hints
Callout blocks for notes, warnings, and other contextual messages. Also supports standard GitHub markdown alerts.
Syntax
{{% hint [info|success|warning|danger] %}}
Markdown content
{{% /hint %}}Or using markdown alerts
> [!NOTE|TIP|IMPORTANT|WARNING|CAUTION]
> Markdown contentExample
Default hint
Without a specified type.
Info
Use for supplementary information that helps the reader.
Success
Use to highlight a recommended approach or positive outcome.
Warning
Use for important caveats or potential issues.
Danger
Use for critical warnings about breaking changes or data loss.
Markdown Alerts
Standard GitHub markdown alert syntax is also supported:
Set
disablePathToLower = truein your config to preserve URL casing.
The
unsafe = truegoldmark setting is required for Mermaid and KaTeX shortcodes.
Service worker support is experimental and may change in future releases.
Enabling
BookPortableLinks = 'error'will fail the build if any markdown link targets are missing.
Mermaid
Render diagrams and charts with Mermaid. The library is loaded automatically on first use.
Diagram theme follows the site theme through the --mermaid-theme CSS variable. Override it in assets/styles/custom.css to use another Mermaid theme.
Override Mermaid initialization by creating
assets/mermaid.jsonin your project. Athemeset there takes precedence over the CSS variable.
Syntax
Use fenced code blocks (recommended) or the shortcode
```mermaid
graph LR
A --> B
```{{< mermaid [class="..."] >}}
graph LR
A --> B
{{< /mermaid >}}Examples
flowchart TD A[Content Files] --> B[Hugo Build] B --> C[HTML Output] B --> D[Search Index] B --> E[RSS Feed]sequenceDiagram Browser->>Hugo: Request page Hugo->>Theme: Apply template Theme->>Browser: Rendered HTML Browser->>Browser: Load shortcodespie title Theme Assets "SCSS" : 8 "HTML Templates" : 30 "JavaScript" : 3 "i18n Files" : 35gitGraph commit id: "init" commit id: "add theme" branch feature checkout feature commit id: "add docs" commit id: "add config" checkout main merge feature commit id: "deploy"
Explore more diagram types on the Mermaid documentation.
Steps
Render an ordered list as a series of numbered steps with visual connectors.
Syntax
{{% steps %}}
1. ## Step Title
Step description...
2. ## Step Title
Step description...
{{% /steps %}}Example
Create your site
Run
hugo new site my-docsto scaffold a new Hugo project.Add the theme
Clone or add hugo-book as a submodule in your
themes/directory.Write content
Add markdown files under
content/docs/. Each file becomes a page in the sidebar menu.Deploy
Run
hugoto build the site. The output is in thepublic/directory, ready for any static hosting.
Tabs
Organize content by context, for example installation instructions for each supported platform.
Syntax
{{< tabs >}}
{{% tab "First" %}} Markdown content {{% /tab %}}
{{% tab "Second" %}} Markdown content {{% /tab %}}
{{< /tabs >}}Example
brew install hugosudo snap install hugochoco install hugoKaTeX
Render math typesetting with KaTeX.
Activation
KaTeX styles are included on the page by the first use of the shortcode or a katex code block. In order to use delimiters passthrough needs to be configured.
Block Rendering
Three equivalent ways to render display math:
Result:
Inline Rendering
| Syntax | Output |
|---|---|
{{< katex >}}\pi(x){{< /katex >}} | |
\\( \pi(x) \\) |
Parameters
Shortcode and block parameters are the same as original from transform.ToMath. See Hugo documentation
Passthrough
Hugo offers a hook to render math as passthrough, without codeblocks or shortcodes. See configuration in Hugo documentation.
hugo.yamlmarkup:
goldmark:
extensions:
passthrough:
enable: true
delimiters:
block:
- ['\[', '\]']
- ['$$', '$$']
inline:
- ['\(', '\)']layouts/_markup/render-passthrough.html{{/*- $opts := dict "displayMode" (eq .Type "block") -*/}}
{{/*- (transform.ToMath .Inner $opts) -*/}}Styles
Built-in Themes
Theme comes with a set of predefined color schemes, Use BookTheme parameter in your site config:
hugo.toml[params]
BookTheme = 'light' # or 'dark', 'auto'| Theme | Description |
|---|---|
light | Default. Light background with dark text |
dark | Dark background (Nord palette) with light text |
auto | Switches between light and dark based on OS |
contrast-light | High contrast light variant |
contrast-dark | High contrast dark variant |
contrast-auto | High contrast, auto-switching |
catppuccin-light | Catppuccin Latte palette |
catppuccin-dark | Catppuccin Frappe palette |
catppuccin-auto | Catppuccin, auto-switching |
ayu-light | Ayu light palette |
ayu-dark | Ayu mirage dark palette |
ayu-auto | Ayu, auto-switching |
The list of themes, except light, dark, and auto is not written in stone and potentially would change in the future.
Custom Theme
A theme is just a block of CSS variables selected by data-theme. You can define your own in assets/styles/custom.css:
assets/styles/custom.css:root[data-theme="mytheme"] {
--body-background: #fafafa;
--body-font-color: #333;
...
}Then set BookTheme = 'mytheme'.
Custom Styles
The file assets/styles/custom.css is loaded last, so it overrides every theme style, in this way you can customize styles without editing Hugo theme sources.
assets/styles/custom.css.book-page {
max-width: 60rem;
}
.book-menu nav {
font-size: 0.9rem;
}CSS Variables
The theme is driven by CSS variables:
- Per-theme colors —
assets/styles/themes.css - Base tokens (font sizes, spacing, etc) —
assets/styles/variables.css
Override any of them in assets/styles/custom.css. To adjust the current theme regardless of which one is active, target :root:
assets/styles/custom.css:root {
--menu-width: 18rem;
}File overrides
Hugo’s lookup order lets you override any theme file by creating the same file in your project:
layouts/: Override templates and partialsassets/: Override CSS and JavaScriptstatic/: Override static files (favicon, images)i18n/: Override or add translations
Inject Partials
The theme provides empty partial templates at key points in the page layout. Override these to inject custom HTML without modifying the base templates.
Create matching files in your project’s layouts/_partials/docs/inject/ directory.
| Partial | Location |
|---|---|
inject/head.html | Inside <head>, e.g. meta tags, stylesheets, scripts |
inject/body.html | Before </body>, e.g. analytics, chat widgets, scripts |
inject/menu-before.html | Before the sidebar menu |
inject/menu-after.html | After the sidebar menu |
inject/content-before.html | Before the page content |
inject/content-after.html | After the page content |
inject/toc-before.html | Before the table of contents |
inject/toc-after.html | After the table of contents |
inject/footer.html | Inside the page footer |
Example
To add a Google Analytics script, create layouts/_partials/docs/inject/head.html
{{ with .Site.Params.googleAnalytics }}
<script async src="https://www.googletagmanager.com/gtag/js?id={{ . }}"></script>
{{ end }}To add a custom banner above every page, create layouts/_partials/docs/inject/content-before.html
<div class="my-banner">
This documentation is for version 2.0. See <a href="/v1/">version 1.0 docs</a>.
</div>