Metadata row

The metadata row is the strip under an article title: the published date, the updated date when it differs, the reading time, and on blog and TIL pages a copy-as-Markdown button, separated by slashes. One component consolidates what other design systems split into separate Timestamp and Readtime components. The kind link above the title is not part of this strip; it belongs to the page header’s kind row.

The row below is the component rendered with this page’s own dates:

Published 4 min read

When to use#

  • Every dated page gets the same strip in the same order: copy button, published date, updated date, reading time, collection badge, tag pills — items toggle on and off, they never reorder
  • The updated date appears only when it differs from the published date; the partial compares the two, so a page never shows a redundant “Updated” entry
  • Section defaults do most of the work — blog pages get the copy button and reading time, TIL pages the copy button — so reach for pageHeader: front matter only when a page genuinely deviates
  • Not a place for new item types: the strip is assembled by the shared partial, and pages never hand-write it

Implementation#

pageHeader:
  showReadingTime: true
  showCopyMarkdown: true
  useLastmod: false
{{/* Normal path: section defaults merged with pageHeader: front matter */}}
{{ partial "entry-title-block.html" . }}

{{/* Direct call when a layout picks the items itself */}}
{{ partial "page-header.html" (dict "page" . "showReadingTime" true "showCopyMarkdown" true) }}
<div class="mt-[var(--space-s)] flex flex-wrap items-center gap-x-[var(--space-xs)] gap-y-[var(--space-2xs)]" data-pagefind-ignore>
  <span class="meta">Published <time datetime="2026-08-16">2026.08.16</time></span>
  <span class="meta" aria-hidden="true">/</span>
  <span class="meta">Updated <time datetime="2026-08-16">2026.08.16</time></span>
  <span class="meta" aria-hidden="true">/</span>
  <span class="meta">4 min read</span>
</div>

The row is the meta template inside layouts/partials/page-header.html, driven by layouts/partials/entry-title-block.html, which sets the section defaults and merges pageHeader: front matter overrides before delegating. The row renders only when at least one item is enabled. The date labels come from the publishedOn and updatedOn i18n keys, the reading time from readingTime. There is no JavaScript in the row itself — the copy button brings its own, documented on Copy as Markdown — and no separate CSS file; items share the .meta class in assets/css/site.css.

Options#

OptionPurpose
showMetaMaster toggle for the whole row on article-variant headers
showDate, showLastmodPublished date; updated date when it differs from the published date
useLastmodReplaces both dates with a single updated date
dateLabel, lastmodLabelText before each date, as an i18n key or a literal
showReadingTimeReading time from Hugo’s word count; also settable per page as show_reading_time
showCopyMarkdownCopy-as-Markdown button at the start of the row
showTagsTag pills at the end of the row

Interface manifest

Kind
Component
Category
Data
Status
Implemented
Implementation
Partial:layouts/partials/page-header.htmllayouts/partials/entry-title-block.htmlCSS:assets/css/site.cssi18n:publishedOnupdatedOnreadingTime

Accessibility#

  • The row is a plain <div> of <span class="meta"> items — display text, not a landmark, and it needs no role
  • Dates are <time> elements with a machine-readable datetime attribute (2026-08-16) behind the displayed house format (2026.08.16), and the labels are locale-aware through the publishedOn and updatedOn i18n keys
  • Reading time is non-interactive display text needing no ARIA; the / separators carry aria-hidden="true", so screen readers skip them
  • Keyboard: only interactive items take focus — the copy button, the collection badge link, the tag pills; a row of dates and reading time has no tab stops
  • Avoid hand-writing the strip in a layout — the separator aria-hidden and the paired datetime formats stay correct only through the shared partial