Most Hugo theming guides will tell you to fork the theme and modify it directly. I am here to tell you that is not necessary and the solution I propose and utilize here in this blog is much simpler and more maintainable. First I will talk about why forking a theme and using that is not what I see as the ideal solution for this use-case:
- It’s boring!
- Making your own theme is fun and will give your blog more personality.
- Having to cater your blog posts to upstream changes in the theme is a shortcut to becoming frustrated with maintaining your blog; it adds unnecessary friction to your life and workflow for blogging.
So, for a site running PaperMod as a git submodule, that approach is a maintenance problem waiting to happen and most importantly, isn’t fun. The cleaner solution is to use Hugo’s override system to inject custom styles without touching the theme directory at all. This gives us full control over the theme and even allows for future post-specific customization.
The Override Pattern
Hugo’s asset pipeline has a well defined load order. Files in your project root take precedence over files in the theme. PaperMod specifically exposes two hooks for this:
assets/css/extended/: any.cssfile dropped here gets automatically concatenated into the final stylesheet after PaperMod’s base styles.layouts/partials/extend_head.html: gets included in<head>on every page, intended for custom fonts, meta tags, or third-party scripts.
This means a full theme restyle requires just two files:
assets/css/extended/terminal.css # all CSS overrides and animations
layouts/partials/extend_head.html # Google Fonts import(s)
The theme submodule stays at its original commit, unmodified. Running git submodule update in the future will never touch these customizations because we
aren’t reliant on any upstream theming, only the underlying structure of Hugo
and PaperMod are necessary!
Implementation
extend_head.html just pulls in the fonts with one line:
<link href="https://fonts.googleapis.com/css2?family=Share+Tech+Mono&family=Orbitron:wght@400;700;900&family=VT323&display=swap" rel="stylesheet">
Then, the CSS file overrides PaperMod’s CSS variables at the :root level; this
itself cascafdes through the entire theme automatically because we override at
root. Setting --theme, --entry, --primary, and --border to your own
values replaces PaperMod’s color scheme without targeting individual components:
:root {
--theme: #020a04;
--entry: #040d06;
--primary: #00ff41;
--border: rgba(0, 255, 65, 0.18);
}
From there it’s standard CSS-typography overrides, animation keyframes for the
scanline effect, syntax highlight class overrides for Chroma. One thing worth
noting here is how Hugo’s syntax highlighter outputs inline styles by default,
which makes it impossible to override via CSS. To fix this, we can set the
following in hugo.toml:
[markup.highlight]
noClasses = false
This switches Chroma to class-based output, so .chroma .k, .chroma .s, etc.
become targetable in the stylesheet.
Result
Three files added to the repo root with the theme submodule untouched:
assets/css/extended/terminal.css
layouts/partials/extend_head.html
hugo.toml # updated with noClasses = false and params
The site rebuilds on next deploy with the full theme applied and I like to think I did a decent job with my theme; feel free to out-do me yourself though if you think you can do better! ;)