_default/list.html is hardwired to paginate .Pages into a card grid — great
for a blog index, wrong for a section that is really a single page with no
children, sourced from a data/*.json file instead of child content.
layout = "list-plain"
Ship a section with title + .Content and nothing else — no pagination, no
card grid, no taxonomy cloud — by setting layout in its _index.md front
matter:
+++
title = "About"
layout = "list-plain"
+++
Hugo picks _default/list-plain.html over _default/list.html for that
section. This is Hugo’s own template-selection mechanism (the layout front
matter field) rather than a theme-specific param, because unlike headerType
or menuType — which pick a partial included from within one fixed entry
template — Hugo has no other way to choose between two candidate top-level
list templates.
The Releases section on this exampleSite uses it: a page with no
children, its content sourced from data/releases.json.
utils/data-items.html
The “does this data file have anything in it” check —
.Site.Data.releases.items | default slice — is easy to end up hand-rolling at
every call site that reads a data/*.json file shaped {"items": [...]}.
utils/data-items.html is a returning partial for it:
{{ $items := partial "utils/data-items.html" "releases" }}
{{ if gt (len $items) 0 }}
...
{{ end }}
It resolves .Site.Data.<name>.items, defaulting safely to an empty slice
when the data file or its items key doesn’t exist — callers check len()
rather than testing for existence directly.
Conditional menu entries reuse this exact partial: the Press nav
link above only renders because data/releases.json has items.