Creating a new Hugo theme

I’ve started playing with Hugo this evening and whilst the documentation is pretty good there aren’t any step by step instructions for creating a new theme. This is how I did it.

The first thing to do is bootstrap a new theme:

hugo new theme michael

This will create a new folder in theme that looks like the following:

.
└── michael
    ├── LICENSE
    ├── archetypes
    │   └── default.md
    ├── layouts
    │   ├── 404.html
    │   ├── _default
    │   │   ├── baseof.html
    │   │   ├── list.html
    │   │   └── single.html
    │   ├── index.html
    │   └── partials
    │       ├── footer.html
    │       ├── head.html
    │       └── header.html
    ├── static
    │   ├── css
    │   └── js
    └── theme.toml

Before we start editing the files in that folder we want to update our site to use this theme. Edit config.toml in the root directory and add theme = "michael" at the bottom so that the file looks like the following:

baseURL = "http://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "michael"

For now we can ignore all of the files in our new theme, except for index.html which is the homepage of our site. Edit layouts/index.html and add the following content:

{{ define "main" }}
  <h1>Hello World</h1>
  <p>This is a test</p>
{{ end }}

Save this file and run hugo server --verbose --watch in the terminal. This will start hugo and have it watch for changes. Any time you save a file, it will rebuild your site. Once it’s running, visit http://localhost:1313/ to view the content that you just created.

This works due to Hugo’s base template functionality. When you bootstrap a theme, it creates layouts/_default/baseof.html with the following contents:

<!DOCTYPE html>
<html>
    {{- partial "head.html" . -}}
    <body>
        {{- partial "header.html" . -}}
        <div id="content">
        {{- block "main" . }}{{- end }}
        </div>
        {{- partial "footer.html" . -}}
    </body>
</html>

You should read the docs to understand how all of this works, but the short version is this; it renders a HTML page, including head.html, header.html, the main block (which we defined in index.html) and footer.html.

head.html, header.html and footer.html are partials, which means that Hugo will read each of those files and insert the contents of the file in place of the partial tag. Partials are stored in layouts/partials, and if you browse that directory you’ll see our three partials in there. Edit layouts/partials/header.html and add the following:

<h1>Site Header</h1>

If you go back to your site at http://localhost:1313/ again now, you should see the site-wide header at the top of the page.

I’m still working on the home page for this site so I haven’t gotten as far as single or list pages yet, but it took me a little bit of reading to learn what’s in this post so far, so I’m publishing as a reminder to myself the next time I need to bootstrap a new theme

Michael is a polyglot software engineer, committed to reducing complexity in systems and making them more predictable. Working with a variety of languages and tools, he shares his technical expertise to audiences all around the world at user groups and conferences. You can follow @mheap on Twitter

Thoughts on this post

Leave a comment?

Leave a Reply