Theming
Restyling with custom properties, and overriding templates.
A theme is two directories: STATIC_DIR for assets and TEMPLATE_DIR for
templates. A file in either replaces the bundled one of the same name, and
anything you do not override keeps coming from the binary. Nothing is forked and
nothing is rebuilt.
make up and make run point both at theme/ with THEME_RELOAD=true, so
writing a theme is editing a file and refreshing the page.
Restyle with CSS
Most stores never need a template. Every colour, size and spacing value in the
default theme is a custom property in one :root block at the top of
styles.css, so rebranding is editing a dozen values.
Copy the default and edit its :root:
cp internal/handler/static/styles.css theme/static/styles.css:root {
--paper: #fffdf8;
--paper-sunk: #f4efe4;
--ink: #241f18;
--ink-soft: #5c5348;
--ink-faint: #8d8375;
--rule: #e2d9c8;
--accent: #7a2e1f; /* buttons, links, prices */
--accent-ink: #fffdf8;
--font: "Iowan Old Style", Georgia, serif;
--radius: 0;
--page: 1000px;
}Your file replaces the bundled one entirely — there is no cascade between them — so start from a full copy rather than a file of just the variables.
To change the logo, drop a logo.svg into STATIC_DIR.
Web fonts
The default theme uses the system font stack: no download and no third-party request. To use a web font, either:
- Self-host it. Put the
.woff2inSTATIC_DIRand reference it from your stylesheet with a/static/...URL. Nothing else changes. - Use a hosted service, such as Adobe Fonts. Set
FONT_CSS_URLto the kit's stylesheet andFONT_ORIGINSto the origins it loads from. Set both or neither. This puts a third-party request on every page, the checkout included.
Either way, set --font in your stylesheet to apply it.
Override templates
Templates override by path: a file at pages/product.gohtml in
TEMPLATE_DIR replaces the default pages/product.gohtml. Start from a copy:
mkdir -p theme/templates/pages
cp internal/handler/templates/pages/products.gohtml theme/templates/pages/| Directory | Holds |
|---|---|
layouts/ |
The public and admin layouts |
partials/ |
Pieces every page can use, such as the product card grid |
pages/ |
The storefront pages |
admin/ |
Everything behind the admin login |
mail/ |
The order emails, which no layout wraps |
Each page file defines content, and replacing a file replaces only the
definitions it names — so a file can override one fragment and leave the rest of
the page alone.
Four things to know before shipping a theme:
- Class names are the contract between templates and stylesheet. Change the markup and keep the names, or change both together.
- Every form needs
{{template "csrf" .CSRFToken}}, or it is refused. - No inline styles or scripts. The CSP allows neither, so CSS goes in a
stylesheet and JavaScript in a
.jsfile, both inSTATIC_DIR. - A missing field or template is an error on that page, not at startup, because Go checks them when a template runs. Render every page you have touched.
Reloading
THEME_RELOAD=true re-reads both directories on every request. It is for
writing a theme and nothing else — leave it off in a deployment. Without it, the
theme is read once at startup: a template that does not parse refuses the boot,
and shipping a change is replacing the files and restarting.