This is the multi-page printable view of this section. .

Return to the regular view of this page.

Components

Every component available for writing, ordered by how often you reach for it.

OINK’s components fall into two groups: the writing primitives you use every day, and the larger components you need for specific situations. Complete multi-page publishing workflows live under Scenario components.

They all follow one contract: semantic HTML, no JavaScript for the non-interactive ones, a defined presentation in print and Markdown output, and a failed build rather than silent degradation when a parameter is invalid.

Everyday writing

Component Purpose Needs JS
Code blocks and groups Filenames, copy, collapse, synchronized tabs On pages with code
Badge Status labels such as Beta or Deprecated No
Kbd Keyboard shortcuts No
Fields Configuration, parameter, and response descriptions No
FileTree Directory structures No

Media

Component Purpose Needs JS
Gallery A grid of related images Reuses the zoom runtime
Image zoom Enlarging screenshots and diagrams Per page when enabled

Layout and structure

Component Purpose
Tabs, cards, steps, and more Tabbed panes, cards, steps, disclosures, carousels

Diagrams and visualization

Component Purpose Runtime
Diagrams and formulae Mermaid, KaTeX, Markmap, PlantUML Per page
ECharts Interactive data charts Per page
Infographic Process and information graphics Per page

Scenario workflows

Scenario Coordinated capabilities
Sequential reading Pager order, head relations, local mathematics
Releases and downloads Facts, checksums, rolling and pinned channels
Landing pages Full-width shell, local data, 21 reusable sections
Book publishing Numbered media, xrefs, indexes, whole-Book print

These scenarios compose several primitives with navigation, data, and output rules. Their pages are the authoritative adoption guides; do not infer a scenario contract from one shortcode example alone.

Shared contract

  • Standard shortcode notation {{</* … */>}}.
  • Nested names (filetree/folder, gallery/image, field) are valid only inside their parent.
  • An invalid parameter fails the build with its source position; strict failure beats silent degradation.
  • Only Fields descriptions accept Markdown; every other public string parameter is plain text.
  • A page that does not use a component never receives its runtime.

1 - Code blocks and Code Groups

Add filenames, exact Copy behavior, wrapping, collapse, and shareable groups to Hugo code examples.

OINK enhances Hugo’s ordinary fenced code blocks without replacing Chroma or requiring a browser highlighter. The server emits the complete code and shell; small page-scoped scripts only enable Copy, visual collapse, and tab state.

Enhanced fences

Add metadata in Hugo’s fence attribute list. A fence without attributes still receives the same responsive shell and its normal Copy default. filename adds a visible header; title is its compatible alias, and setting both is a build error. With neither, OINK uses a compact overlay instead of an empty title row.

Authoring

content/docs/example.md
MARKDOWN
```yaml {filename="hugo.yml" copy="all" lineNos="table" hl_lines="4 7-9" wrap=false collapse=18}
params:
  offlineSearch: true
```

Live result

Rendered result

This block combines a filename, inline line numbers, a stable root ID, line links, and highlighted source lines. Line numbers begin at 12, while hl_lines still addresses the source lines inside the fence:

hugo.yaml
YAML
12markup:
13  highlight:
14    noClasses: false
15params:
16  offlineSearch: true
17  ui:
18    sidebar_menu_foldable: true

Shell parameters

Attribute Values Behavior
filename string Visible filename and accessible group name
title string Alias for filename on an ordinary fence
copy all, command, false, or true Copy policy; true is shorthand for all
wrap true or false Visually wrap long lines without changing text
collapse positive integer Initial maximum number of visible source lines
label string Accessible label when no filename is suitable
id string Stable public block ID and line-anchor prefix

Hugo generic class, safe data-*, aria-*, and global attributes remain on the .td-code root. Names beginning with data-td-code and data-language are reserved. OINK rejects event-handler and inline-style attributes. Use label to override a filename-derived accessible name; a generic aria-label together with label or filename is a build error.

Hugo options

The render hook continues to pass these options to Hugo:

  • lineNos, lineNoStart, and anchorLineNos;
  • hl_lines;
  • tabWidth and style.

Class-based Chroma markup remains inside .highlight and .chroma, so existing token-level overrides keep working. The new stable outer element is .td-code; sites using direct-child selectors such as .td-content > .highlight should update those selectors.

The visible language label normalizes the common bash, sh, and shell lexer aliases to BASH. The original lexer value is still passed to Chroma and retained in data-language.

Diffs deliberately use Chroma’s standard diff lexer rather than a custom transformer:

Authoring

content/docs/configuration.md
MARKDOWN
```diff {filename="hugo.yaml.diff"}
 params:
-  offlineSearch: false
+  offlineSearch: true
```

Rendered result

hugo.yaml.diff
DIFF
 params:
-  offlineSearch: false
+  offlineSearch: true

Copy semantics

Ordinary source defaults to copy="all". console and shell-session default to copy="command": only lines carrying Chroma prompt tokens are copied, and prompt/output tokens are excluded. Use copy="all" when a complete transcript is intentional. command on another language is a build error.

Copy preserves indentation, internal blank lines, and Unicode, removes line numbers, trims only trailing newline characters, and appends exactly one final newline. A session lexer that emits no prompt token reports a localized failure and copies nothing. Set params.disable_click2copy_chroma: true to hard-disable Copy for the entire site.

Copy is shown as a compact icon without adjacent text. Its localized label is still exposed to assistive technology and as a hover tooltip; success and failure also change the icon and update the live status message.

For a multi-line terminal command, include the continuation prompt (normally >) on every continued transcript line. Chroma classifies an unprompted line as output, so copy="command" deliberately excludes it.

The Copy action on this live session copies the two commands, not the prompts or output:

Authoring

content/docs/terminal.md
MARKDOWN
```console {title="Terminal session"}
$ hugo version
hugo v0.164.0+extended darwin/arm64
$ hugo --gc --minify
Total in 742 ms
```

Rendered result

Terminal session
CONSOLE
$ hugo version
hugo v0.164.0+extended darwin/arm64
$ hugo --gc --minify
Total in 742 ms

Wrapping and collapse

wrap=true changes presentation only; copied source is untouched. It is incompatible with Chroma’s table line-number layout because separately wrapped gutter and source cells would drift. Use inline line numbers or disable wrap. OINK fails the build instead of silently misaligning them.

collapse=N is progressive enhancement. The server always emits all source; the browser clips only after it can measure the Nth real Chroma line. Without JavaScript, in assistive technology, and in print, the listing remains complete. Reduced-motion preferences disable the height animation.

The first example wraps a long value without altering copied text:

Authoring

content/docs/downloads.md
MARKDOWN
```text {filename="config/artifacts.env" wrap=true}
ARTIFACT_URL=https://downloads.example.com/releases/2026/08/oink-complete-offline-distribution-arm64.tar.zst
CHECKSUM=sha256:6d3dce4f7acb18f586469adcb80ab35f3e859f9837786e151cfbc2b3c0f587b2
```

Rendered result

config/artifacts.env
TEXT
ARTIFACT_URL=https://downloads.example.com/releases/2026/08/oink-complete-offline-distribution-arm64.tar.zst
CHECKSUM=sha256:6d3dce4f7acb18f586469adcb80ab35f3e859f9837786e151cfbc2b3c0f587b2

The second emits all lines on the server but initially shows six in a browser:

Authoring

content/docs/configuration.md
MARKDOWN
```yaml {filename="hugo.yaml" collapse=6}
baseURL: https://docs.example.com/
title: Product Documentation
defaultContentLanguage: en
languages:
  en:
    label: English
    weight: 1
  zh:
    label: 简体中文
    weight: 2
params:
  offlineSearch: true
```

Rendered result

hugo.yaml
YAML
baseURL: https://docs.example.com/
title: Product Documentation
defaultContentLanguage: en
languages:
  en:
    label: English
    weight: 1
  zh:
    label: 简体中文
    weight: 2
params:
  offlineSearch: true

Set a page-unique explicit id when publishing line-number links. IDs cannot contain ASCII whitespace or control characters and cannot collide with another code component’s generated viewport, tab, panel, title, or line-anchor ID. OINK reports any such collision as a build error:

Authoring

content/docs/server.md
MARKDOWN
```go {id="server-start" lineNos="inline" anchorLineNos=true}
func start() {}
```

Rendered result

GO
1func start() {}

OINK derives unique line-anchor prefixes from that ID. Generated IDs are safe inside a page but depend on the block ordinal and are not a permalink contract; inserting an earlier fence can change them.

Code Groups

Use code-group when examples are alternatives rather than independent tabs:

Authoring

content/docs/install.md
GO-HTML-TEMPLATE
{{< code-group id="docs-install-client" sync="docs-package-manager" persist=false
    label="Choose a package manager" copy="all" >}}
  {{< code-tab title="npm" value="npm" lang="bash" >}}
npm install @example/client
  {{< /code-tab >}}
  {{< code-tab title="pnpm" value="pnpm" lang="bash" selected=true >}}
pnpm add @example/client
  {{< /code-tab >}}
  {{< code-tab title="yarn" value="yarn" lang="bash" >}}
yarn add @example/client
  {{< /code-tab >}}
{{< /code-group >}}

Rendered result

npm BASH
npm install @example/client
pnpm BASH
pnpm add @example/client
yarn BASH
yarn add @example/client

code-tab contains raw code, not Markdown. OINK removes the framing newline and closing-shortcode indentation while preserving all source whitespace inside. Because a Markdown formatter can otherwise reflow that raw body, put <!-- prettier-ignore --> immediately before each live code-group when using Prettier, as in the examples below.

Group and tab parameters

Every group requires a page-unique lower-case id. Optional sync, persist, label, copy, wrap, and collapse values apply to the group; the last three are inherited defaults. persist defaults to true.

Every child requires a plain-text title and stable lower-case value. lang defaults to text; selected, copy, wrap, collapse, and the Hugo highlight options can override group defaults. A group cannot be empty, repeat a value, or contain more than one selected=true child. Filenames are omitted inside groups because the tab itself identifies the example.

Selection, sync, and persistence

A selected panel has the public hash #<group-id>-<value>, for example #install-client-pnpm. Initial selection priority is URL hash, saved value, selected=true, then the first child.

Groups sharing sync select the same value when that value exists in each group; a peer missing it stays unchanged. A user selection updates the hash with replaceState and saves the value when persistence is enabled. Visiting a shared hash activates the requested examples without overwriting the reader’s saved preference. persist=false disables storage, not in-page synchronization.

Live synchronized groups

The rendered install group above and the run group below share the same sync key. Choose a package manager in either group and the other follows. The first group’s npm, pnpm, and yarn panels also have shareable hashes.

Authoring

content/docs/run.md
GO-HTML-TEMPLATE
{{< code-group id="docs-run-client" sync="docs-package-manager" persist=false >}}
  {{< code-tab title="npm" value="npm" lang="bash" >}}
npm run docs:dev
  {{< /code-tab >}}
  {{< code-tab title="pnpm" value="pnpm" lang="bash" selected=true >}}
pnpm docs:dev
  {{< /code-tab >}}
  {{< code-tab title="yarn" value="yarn" lang="bash" >}}
yarn docs:dev
  {{< /code-tab >}}
{{< /code-group >}}

Rendered result

npm BASH
npm run docs:dev
pnpm BASH
pnpm docs:dev
yarn BASH
yarn docs:dev

Output and compatibility

Print hides controls and tab rows, expands every listing, and places each group title before its code. Markdown output turns every grouped or legacy tab into a readable titled fence and chooses a longer delimiter when source contains backticks. Feeds and other non-interactive outputs use stacked examples. Pages without applicable code or tabs do not load their runtimes.

Existing tabpane source and its td-tp-persist:* browser keys remain compatible. Prism remains a legacy alternative and does not receive Enhanced Code Blocks or Code Groups. Specialized mermaid, math, chem, markmap, and plantuml hooks continue using their own renderers.

2 - Badge

Add compact, semantic status labels without custom colors or JavaScript.

Use Badge to place a short status beside a feature, option, or release name. The author chooses a semantic tone; Oink maps it to theme tokens that retain contrast in light and dark modes.

When to use

Badge works well for lifecycle states such as Beta, New, Experimental, and Deprecated. Keep the text explicit: color supplements the label and never replaces it. Use ordinary prose or an alert when the status needs explanation, instructions, or a deadline.

Quick start

Source

GO-HTML-TEMPLATE
{{< badge text="Beta" tone="warning" >}}
{{< badge text="Deprecated" tone="danger" outline=false >}}
{{< badge text="v0.3" tone="info" link="/blog/release/" >}}

Rendered result

Neutral Info Supported Beta Deprecated v0.3

The final badge is a link. The others are static inline labels.

Parameters

Badge parameters

text , string , required

A nonempty string shown to the reader.

tone , enum , default: neutral

One of neutral, info, success, warning, or danger.

link , URL

A validated internal, relative, HTTP(S), or mailto: destination. When set, the Badge becomes a link.

outline , boolean , default: true

Set to false to select the filled treatment.

Pass booleans without quotes. For example, use outline=false, not outline="false". Unknown parameters and invalid tone or link values stop the Hugo build and report the source position.

Semantics and fallback

A static badge renders as a span; a linked badge renders as an a. Oink does not make it a live status region, so adding a badge does not create unexpected screen-reader announcements. Its visible text remains present in every output: Markdown uses emphasized text (and preserves the link), while print and RSS use static inline content. Badge loads no JavaScript.

Deliberate limits

Badge does not accept arbitrary colors, CSS classes, styles, or event handlers. Version one also has no icon parameter. Use a concise textual label now; content icons can receive a separate public API after their naming, licensing, accessibility, and Markdown fallback contracts are settled.

3 - Kbd

Write keyboard shortcuts as accessible, static key sequences.

Use Kbd to distinguish literal keys and shortcuts from surrounding prose. It renders semantic HTML, remains readable in Markdown and print, and needs no JavaScript.

When to use

Use Kbd for keys the reader should press, including multi-key shortcuts. Use inline code for commands, option names, or text the reader should type; those are not physical or virtual keys.

Quick start

Source

GO-HTML-TEMPLATE
Press {{< kbd "Ctrl" "K" >}} to open search.
Use {{< kbd "⌘" "Shift" "P" >}} to open the command palette.

Rendered result

Press Ctrl with K to open search. Use with Shift with P to open the command palette, or press Alt with Enter to apply an action.

Interface

Kbd accepts one or more nonempty positional strings:

GO-HTML-TEMPLATE
{{< kbd "key" >}}
{{< kbd "first key" "second key" "third key" >}}

It has no named parameters. Quotes are required because every key must be a string. Missing keys, blank strings, named arguments, or non-string values stop the build with the source position.

Use the label printed on the relevant platform when the distinction matters. For cross-platform instructions, name the platform in prose instead of placing alternatives inside one key sequence.

Semantics and fallback

HTML contains one nested kbd element per key. Visual plus signs are hidden from assistive technology; a localized word separates the keys for screen readers. Markdown, print, and RSS use an unambiguous sequence such as Ctrl + K. The instruction remains complete when CSS or JavaScript is absent.

Deliberate limits

Kbd represents simultaneous key sequences only. It does not model menus, gesture input, key remapping, platform detection, or an interactive shortcut recorder. Explain sequential actions in prose: “press Escape, then Enter.”

4 - Fields and Field

Describe configuration, parameters, properties, and response fields with responsive semantic HTML.

Use fields with field children to document named values and their metadata. The component favors a responsive definition list over a wide fixed table, so long names and descriptions remain usable on narrow screens.

When to use

Fields works for configuration keys, command or API parameters, object properties, and response members. Use a regular Markdown table when readers must compare many rows across the same columns. Use prose when the entries are steps rather than definitions.

Quick start

Source

GO-HTML-TEMPLATE
{{< fields label="Search configuration" >}}
  {{< field name="offlineSearch" type="boolean" required=true default=true >}}
  Builds a **local** search index and command palette.
  {{< /field >}}

  {{< field name="offlineSearchMaxResults" type="integer" default=10 >}}
  Limits the number of visible results.
  {{< /field >}}
{{< /fields >}}

Rendered result

Search configuration

offlineSearch , boolean , required , default: true

Builds a local search index and command palette.

offlineSearchMaxResults , integer , default: 10

Limits the number of visible results while retaining keyboard navigation.

searchPlaceholder , string , default: ""

Sets optional placeholder text. The empty-string default remains visible.

theme.components.media.previewMaximumWidthInCharacters , string , default: auto

This deliberately long field name demonstrates wrapping without widening the page.

Descriptions accept Markdown, including links, emphasis, inline code, and lists. Keep each description self-contained because Markdown output presents each one beneath its metadata.

Fields parameters

fields parameters

label , string

A nonempty visible label associated with the complete definition list.

The container must have at least one direct field child. Text or another shortcode directly inside fields stops the build.

Field parameters

field parameters

name , string , required

A nonempty string identifying the field.

type , string

A nonempty type label such as boolean, string[], or duration.

required , boolean , default: false

When true, adds the literal required marker. The marker is untranslated API vocabulary.

default , scalar

A string, boolean, integer, or floating-point value. false, 0, and "" are preserved.

Every field also requires a nonempty body. It must be a direct child of fields. Parameter names and types are validated at build time, and unknown parameters are errors.

Semantics and fallback

HTML uses dl, dt, and dd. Each entry stacks a header row — the field name followed by its type, required, and default markers — above the description, and hairline dividers separate entries. The required and default labels stay in English in every locale. The optional label names the definition list for assistive technology. Markdown emits an indented bullet list with code-formatted names, types, and defaults; print and RSS retain every definition. No JavaScript is loaded.

Deliberate limits

Version one does not implement kind, deprecated, since, location, or per-field links. It also does not parse TypeScript or an API schema inside Hugo. An external generator may emit these shortcodes later, keeping compiler and schema runtimes outside the theme while preserving this output contract.

5 - FileTree

Present repository and directory structures as semantic, progressively disclosed lists.

Use FileTree to explain the part of a repository or directory layout that matters to the reader. Folders use native disclosure controls in interactive HTML; every output retains the complete nested structure.

When to use

FileTree works best for curated structures in setup guides, architecture overviews, and contribution instructions. Use a code block for literal command output that should be copied verbatim. Describe generated or highly dynamic trees in prose instead of committing a large snapshot that will quickly drift.

Quick start

Source

GO-HTML-TEMPLATE
{{< filetree label="Repository structure" >}}
  {{< filetree/folder name="content" open=true >}}
    {{< filetree/file name="_index.md" >}}
    {{< filetree/folder name="docs" open=true >}}
      {{< filetree/file name="getting-started.md" >}}
    {{< /filetree/folder >}}
  {{< /filetree/folder >}}
  {{< filetree/file name="hugo.yml" link="/docs/getting-started/" >}}
{{< /filetree >}}

Rendered result

Repository structure

The blog folder starts closed. Activate its summary with a pointer, Enter, or Space to reveal the child file; this behavior comes from the native details element rather than a custom script.

Root parameters

filetree parameters

label , string

A nonempty visible label associated with the root list.

The root accepts only direct filetree/folder and filetree/file children. Add at least one meaningful entry rather than publishing an empty tree.

Folder and file parameters

filetree/folder parameters

name , string , required

A nonempty visible directory name.

open , boolean , default: false

Controls the initial interactive HTML state.

filetree/file parameters

name , string , required

A nonempty visible file name.

link , URL

A validated internal, relative, HTTP(S), or mailto: destination.

A folder can contain folders and files recursively. A file cannot contain children. Unknown parameters, text between children, or a child outside an allowed parent stops the build with its source position.

Semantics and fallback

The structure is a nested ul. Interactive folders add native details and summary; Oink deliberately does not declare role="tree", because that ARIA widget would require a complete arrow-key navigation model. Print and RSS expand all folders. Markdown becomes a nested list with linked file names where applicable. No JavaScript is loaded.

Deliberate limits

FileTree is author-controlled and never reads a local directory during a Hugo build. This keeps builds safe and reproducible. Version one also has no public badge or icon parameters for entries; the built-in folder and file glyphs are presentational theme details, not content APIs.

6 - Gallery

Arrange related images in a responsive static grid that can reuse Image Zoom.

Gallery groups related images in a responsive grid. It is static-first: images, alternative text, and captions remain available without JavaScript. When Image Zoom is enabled, Gallery reuses the same dialog instead of loading another lightbox.

When to use

Use Gallery to compare a small set of screenshots, states, or related visual examples. Use a single image when sequence and comparison do not matter. Use Carousel when the content intentionally needs slide navigation and hiding noncurrent items is acceptable.

Quick start

Source

GO-HTML-TEMPLATE
{{< gallery columns=3 label="OINK screenshots" >}}
  {{< gallery/image
    src="images/content-primitives/oink.webp"
    alt="OINK documentation overview"
    caption="Documentation overview"
  >}}
  {{< gallery/image
    src="/images/feedback.png"
    alt="OINK feedback interface"
    caption="Feedback controls"
  >}}
{{< /gallery >}}

Rendered result

This page enables Image Zoom. Activate any image to inspect it in the shared dialog. With JavaScript disabled, the same three figures remain visible in the same reading order.

gallery parameters

columns , integer , default: 2

An unquoted value from 1 through 4; this is the desktop maximum.

label , string

A nonempty visible label associated with the gallery list.

The container requires at least one direct gallery/image child and accepts no ordinary body text. Small viewports reduce the effective column count without changing the requested desktop maximum.

Image parameters

gallery/image parameters

src , image URL , required

A validated page, global, static, or remote image URL.

alt , string , required

Meaningful nonempty plain text describing the image.

caption , string

Nonempty plain text shown below the image.

Gallery records intrinsic width and height for local Hugo resources when available and adds lazy loading. It accepts a remote source URL but never downloads that image during the Hugo build, so remote dimensions remain unknown. Captions do not render Markdown; keep them concise and move rich explanation into nearby prose.

Semantics and fallback

HTML uses a labeled ul of figure, img, and optional figcaption elements. Each image retains its own alternative text; the gallery label names the collection. Markdown emits ordinary images followed by italic captions. Print and RSS render sequential static figures. Gallery has no private JavaScript runtime: it only marks its images for Image Zoom when that page-level feature is enabled.

Deliberate limits

Gallery does not crop images to a forced aspect ratio, reorder them by breakpoint, hide overflow, or provide slide navigation. It has no Gallery-specific lightbox. These constraints preserve document order and keep the fallback complete.

7 - Image Zoom

Let readers inspect meaningful standalone images with an optional native dialog.

Image Zoom progressively enhances eligible content images with one native dialog. It is useful for screenshots and architecture diagrams whose details may be hard to read at the document width. The original image remains complete when JavaScript or dialog support is unavailable.

When to use

Enable zoom when a reader benefits from seeing the source image at a larger size. Prefer a purpose-built crop or a clearer diagram when enlargement does not solve the readability problem. Decorative icons, logos embedded in prose, and linked thumbnails should retain their existing behavior.

Enable the feature

Image Zoom is disabled by default. Enable it for the whole site in Hugo configuration:

YAML
params:
  ui:
    image_zoom:
      enable: true

A page can override the site value in its front matter with the same structure. Use a real boolean:

YAML
params:
  ui:
    image_zoom:
      enable: false

Oink only includes the JavaScript runtime and dialog on an enabled page that has an eligible image. Enabling the switch alone adds no runtime to a text-only page.

Quick start

Source

Ordinary standalone Markdown images are eligible. The named imgproc form is useful when Oink should generate a smaller preview but open the original:

GO-HTML-TEMPLATE
{{< imgproc
  src="images/content-primitives/oink.webp"
  command="Fit"
  options="640x320"
  alt="OINK local-first documentation preview"
>}}
A processed preview with a **Markdown caption**.
{{< /imgproc >}}

Rendered result

Activate the image with a pointer, Enter, or Space. Close the dialog with Escape, the visible close button, or the backdrop.

OINK local-first documentation preview

The document displays a processed preview. Image Zoom opens the original resource, and closing the dialog restores focus to this trigger.

An image inside a link is deliberately skipped and remains a link:

Linked OINK image remains a link

Eligible images

Oink enhances a meaningful image when all of these conditions hold:

  • The image is standalone in a paragraph or figure, or Gallery marks it explicitly.
  • It has a nonempty alt value and usable source.
  • It is not inside a link, button, or element marked data-no-zoom.
  • It is not marked aria-hidden="true", role="presentation", or role="none".

Inline images among text and empty-alt decorative images are skipped. Authors can add data-no-zoom to an image or ancestor in trusted HTML when an otherwise eligible image should not open.

Named imgproc parameters

Named imgproc parameters

src , resource path , required

An exact page or global image resource.

command , enum , required

One of Fit, Resize, Fill, or Crop.

options , string , required

Nonempty Hugo image-processing options, such as 640x320.

alt , string

Meaningful alternative text. It is required for content images and omitted only with decorative=true.

decorative , boolean , default: false

When true, alt must be absent and Image Zoom is suppressed.

The optional shortcode body is a Markdown caption. The historical three-value positional imgproc form remains compatible, but new content should use the named form so alternative text is enforced at build time.

Interaction and fallback

Progressive enhancement wraps an eligible image in a real button with aria-haspopup="dialog". The native dialog moves focus to its close button, supports Escape, copies the image’s alternative text and direct caption, and restores focus after closing. Without JavaScript or HTMLDialogElement, the image and caption remain ordinary static content. Markdown, print, and RSS do not include dialog controls.

Deliberate limits

Version one does not implement dragging, panning, wheel zoom, editing, or previous and next image navigation. It also never downloads a remote image at build time. Use Gallery to group related images while reusing this same dialog.

8 - Shortcodes

Use OINK’s local-first content components safely and accessibly.

Shortcodes add behavior that ordinary Markdown cannot express. OINK retains the core Docsy components and adds locally served charts, terminal recordings, infographics, carousels, cards, and disclosure widgets. Browser runtimes load only on pages that use them.

Prefer Markdown for headings, prose, lists, links, tables, and images. A shortcode becomes part of the content API: changing its name or parameters can break every page that calls it.

Shortcode delimiters

Hugo supports two forms:

  • {{< name >}} uses standard delimiters and passes inner content as-is;
  • {{% name %}} uses Markdown delimiters and renders inner Markdown in the surrounding content context.

Use the form documented for the component. Nesting, indentation, and blank lines matter, especially inside lists and blockquotes. In examples, the /* ... */ escape prevents Hugo from executing the displayed shortcode.

blocks/* shortcodes

Block shortcodes compose full-width landing pages. Their color argument uses OINK/Bootstrap semantic colors or a project-defined block style. Their height argument accepts the values documented for each block.

blocks/cover

Creates a hero from the page bundle image matching *background* and optional *logo*:

MARKDOWN
{{< blocks/cover title="OINK" subtitle="Local-first documentation"
    color="dark" height="max" >}} [Get started](/docs/tutorial/){ .btn .btn-lg
.btn-primary } {{< /blocks/cover >}}

image_anchor and logo_anchor control image cropping; byline attributes the image. Heights are auto, min, med, max, or full. Essential hero text must remain readable without the background.

blocks/lead

Creates a prominent introductory band:

MARKDOWN
{{% blocks/lead color="primary" height="min" %}} OINK builds the whole
documentation experience with Hugo Extended. {{% /blocks/lead %}}

The height accepts auto, min, med, max, or full.

blocks/section

Creates a general landing-page band:

MARKDOWN
{{% blocks/section color="light" type="row" height="auto" %}}

### One section

Use ordinary Markdown inside the block. {{% /blocks/section %}}

type selects the container treatment; height uses the block height values. Keep heading levels consistent with the page outline.

blocks/feature

Creates one feature cell, normally inside a section:

MARKDOWN
{{% blocks/feature icon="fa-solid fa-box-archive"
    title="Works offline" url="/docs/about/local-first/"
    url_text="Read the design" %}} All required browser assets are pinned and
served locally. {{% /blocks/feature %}}

The icon is decorative; title and link text must carry the meaning.

Adds a link from one block to the next. It must be nested inside a block. Set an explicit id when the generated target must remain stable.

Below-navbar layout correction

Blocks that begin directly below fixed navigation use td-below-navbar/td-anchor-no-extra-offset to compensate for navbar height. Reuse these classes rather than adding arbitrary top margins; verify direct fragment navigation after changing navbar dimensions.

Helper shortcodes

alert

The legacy alert shortcode remains available:

MARKDOWN
{{% alert title="Compatibility note" color="warning" %}} Prefer Markdown
blockquote alerts for new content. {{% /alert %}}

color maps to a Bootstrap alert suffix. New content should generally use the Markdown alert syntax described in Adding Content.

Alerts, indentation, and examples

Keep the opening and closing shortcode aligned with their surrounding list or blockquote. Leave a blank line around block Markdown. If an example must show a shortcode literally, escape its delimiters rather than wrapping an active call in another component.

pageinfo

Renders an informational panel around Markdown:

MARKDOWN
{{% pageinfo color="info" %}} This page describes a preview interface.
{{% /pageinfo %}}

Use a semantic alert for warnings; pageinfo is intended for contextual page information.

imgproc

Processes an image from the current page bundle:

MARKDOWN
{{% imgproc "architecture" Fit "960x540" %}} OINK runtime architecture.
{{% /imgproc %}}

Commands are Fit, Resize, Fill, and Crop. The third argument follows Hugo image-processing syntax. The inner text becomes a caption, and a resource params.byline is appended when present. Always provide useful alternative or adjacent text.

swaggerui

Embeds the locally vendored Swagger UI runtime:

MARKDOWN
{{< swaggerui src="/openapi.yaml" >}}

Use a same-origin specification for offline and CSP-safe deployments. A remote src is an explicit network dependency and can expose reader metadata to that host. Only one Swagger UI instance should be placed on a page with the current compatibility shortcode.

redoc

Embeds the locally vendored Redoc runtime:

MARKDOWN
{{< redoc "openapi.yaml" >}}

The first argument is a page-relative, site-relative, or explicit HTTP specification. The optional second argument contains Redoc element options. Treat specification content as reviewed input and test large schemas on mobile.

iframe

Embeds another page:

MARKDOWN
{{< iframe src="/demo/" name="demo" id="demo-frame"
    sandbox="allow-scripts allow-same-origin" >}}

Set a descriptive name, a unique id, a fallback sub message, and the narrowest viable sandbox. The defaults support width and automatic-height behavior, but cross-origin documents cannot always be measured. An iframe is a security and privacy boundary, not a general layout tool.

OINK content components

The following components are additions carried by OINK. Each runtime is pinned in VENDOR.json and loaded on demand from the same origin.

details

Creates an accessible disclosure:

MARKDOWN
{{% details title="Show migration notes" closed="false" %}} The body accepts
Markdown. {{% /details %}}

closed defaults to true. Use a concise summary and do not hide mandatory instructions inside a closed disclosure.

steps

steps presents a sequence with automatically generated numbers and a visual guide line. Write ordinary Markdown headings and content inside the shortcode; do not type the numbers yourself.

Create the content

Write one direct child heading for each step, followed by any Markdown content that belongs to it.

Check the sequence

Move, add, or remove whole steps. The displayed numbers update automatically.

Publish the result

Verify the sequence on narrow screens and in both color themes.

Use Markdown shortcode delimiters so Hugo renders the inner content:

MARKDOWN
{{% steps %}}

### Create the content

Add the first instruction.

### Check the sequence

Add the next instruction. The number is generated automatically.

#### Optional detail {class="no-step-marker"}

This heading belongs to the current step and does not consume a number.

### Publish the result

Add the final instruction.

{{% /steps %}}

Every direct child heading from h2 through h6 becomes a step. Add class="no-step-marker" when a direct child heading is a subsection of the current step. Keep the same heading level for peer steps, preserve a logical page outline, and avoid nesting one steps block inside another.

asciinema

Plays an asciinema .cast recording:

MARKDOWN
{{< asciinema file="casts/install.cast" speed="1.25"
    markers="0:Start,18:Verify" fit="width" >}}
images/install.cast

The window title uses title when supplied and otherwise displays file. Other important parameters include theme, autoplay, loop, preload, speed, startAt, poster, cols, rows, idleTimeLimit, pauseOnMarkers, markers, and fit (width, height, both, or none). Local recordings can come from Hugo assets or a site-relative URL. Avoid autoplay, remove secrets from terminal history, and provide nearby text for essential steps.

echarts

Apache ECharts is a full visualization system rather than a one-paragraph shortcode. Its advanced guide documents the wrapper, structured options, themes, responsive behavior, accessibility, and trusted callback boundary:

The shortcode body accepts a JSON or YAML options object. Use height, theme, and full only as described in the dedicated guide.

infographic

AntV Infographic has its own advanced guide because template choice, DSL structure, themes, visual semantics, and accessibility need more than an inline example:

The shortcode body contains the Infographic DSL. Use height and full as documented there, and keep an equivalent textual explanation beside every essential visualization.

doc-cards and nav-cards

Both containers accept cols from 1 through 4. Their child cards accept title, link, image, alt, icon, desc, accent, and badge:

MARKDOWN
{{< nav-cards cols="2" >}}
{{< nav-card title="Get started" link="/docs/tutorial/"
      icon="fa-solid fa-rocket" desc="Build with Hugo {version}." >}} {{< nav-card title="Architecture" link="/docs/about/architecture/"
      badge="Design" >}}
{{< /nav-cards >}}

doc-card/doc-cards share the rendering contract and suit editorial content; nav-card/nav-cards signal navigation. Description tokens such as {version} resolve from site parameters. Card images are lazy-loaded; supply meaningful alt text unless the image is decorative.

Places doc-card elements in a keyboard-scrollable carousel:

MARKDOWN
{{< doc-carousel label="Release highlights" >}}
{{< doc-card title="Local assets" >}}No CDN required.{{< /doc-card >}}
{{< doc-card title="Bilingual" >}}Stable English and Chinese
routes.{{< /doc-card >}} {{< /doc-carousel >}}

label names the region for assistive technology. Previous/next buttons are localized. Do not place information only in an off-screen card; the track must remain usable without script.

param

Prints a page parameter, falling back through Hugo’s Page.Param rules to site configuration:

MARKDOWN
OINK version {{< param version >}}.

A missing parameter fails the build. Use param for scalar display values, not for injecting unreviewed HTML. The internal _param compatibility shortcode also performs numbered placeholder replacement for legacy content.

Tabbed panes

Tabs group equivalent representations, such as YAML/TOML/JSON configuration. They must not hide sequential steps or unrelated choices.

MARKDOWN
{{< tabpane text=true persist=lang >}}
{{< tab header="YAML" lang="yaml" >}} params: offlineSearch: true
{{< /tab >}} {{< tab header="TOML" lang="toml" >}} [params]
offlineSearch = true {{< /tab >}} {{< /tabpane >}}

Selection persistence is local to the browser. persist accepts header, lang, or disabled. The deprecated persistLang should not be used in new content.

Shortcode details

text=true renders inner content as prose rather than highlighted code. right=true aligns tabs to the end. langEqualsHeader=true derives language identifiers from headers. Pane defaults can be overridden per tab.

tabpane

The parent validates boolean and persistence parameters, builds unique IDs, and ensures a selected tab. Use one disabled header tab only when it adds a useful group label.

tab

tab must be inside tabpane. It accepts header, selected, lang, highlight, text, right, and disabled. Only one tab should be selected. Translate reader-facing headers, but keep language identifiers stable.

Code Groups

Use code-group/code-tab for code-only alternatives that need stable public hashes, synchronized values, and exact Copy behavior. Unlike legacy tabpane, each child has a required machine value, and non-interactive outputs expand every example. Read Code blocks and Code Groups for the complete parameter and persistence contract.

Card panes

The legacy cardpane/card pair lays out Bootstrap-style cards. New navigation surfaces should prefer OINK content cards, but existing Docsy content can keep the compatibility component.

Shortcode card: textual content

MARKDOWN
{{% cardpane %}}
{{% card header="Note" title="Local build" footer="Verified" %}} Markdown
**content**. {{% /card %}} {{% /cardpane %}}

header, title, subtitle, and footer accept rendered text. Keep equal cards concise and avoid using cards as a replacement for headings.

Shortcode card: programming code

Set code=true and optionally lang/highlight:

MARKDOWN
{{< cardpane >}} {{< card code=true header="Go" lang="go" >}}
fmt.Println("OINK") {{< /card >}} {{< /cardpane >}}

Card groups

Adjacent cards in cardpane form a responsive group. Test unequal text length, mobile stacking, code overflow, and both language variants.

Include external files

The readfile shortcode reads a repository file at build time and either renders it as Markdown or highlights it as code. The path is relative to the current content file unless it begins with /.

Reuse documentation

MARKDOWN
{{% readfile "includes/installation.md" %}}

Included Markdown is not an independent published page and is exempt from the page-pair audit. If shared prose is reader-facing, create and select language-specific include files deliberately; Hugo cannot translate an include.

Installation

Keep reusable fragments under an includes/ directory near their callers. Document ownership and avoid deep include chains: readers and reviewers should be able to locate the source quickly.

Include code files

MARKDOWN
{{< readfile file="includes/config.yaml" code="true" lang="yaml" >}}

code=true highlights the file with lang. Never include secrets, generated credentials, or untrusted paths.

Error reporting

A missing file fails the build. draft=true replaces that failure with a visible draft warning, which is suitable only during authoring and must not reach a release build.

Conditional text

conditional-text selects content using params.buildCondition:

MARKDOWN
{{% conditional-text include-if="enterprise,preview" %}} This paragraph
appears only in matching builds. {{% /conditional-text %}}

include-if and exclude-if accept condition lists. A condition cannot appear in both. Use the feature for genuinely different published variants, not for language selection; multilingual content belongs in translated page files.

9 - Diagrams and formulae

Add local diagrams, mind maps, and scientific formulae to a page.

OINK supports KaTeX, Mermaid, Markmap, PlantUML, and Diagrams.net. KaTeX, Mermaid, and Markmap use build-time or same-origin resources shipped with the theme. PlantUML and the Diagrams.net editor require an explicitly configured service endpoint; they do not silently default to a public service.

LaTeX support with KaTeX

KaTeX renders TeX mathematics for the web. Hugo’s embedded KaTeX support can render formulae at build time, so readers do not need a remote math service.

Inline formulae

Inline formulae use the passthrough delimiter pairs configured in Goldmark. Keep surrounding spaces and punctuation outside the formula when possible.

Formulae in display mode

Use a math code block for a formula on its own line:

MARKDOWN
```math
E = mc^2
```
E=mc2E = mc^2

Activating KaTeX support

math and chem code blocks use theme render hooks automatically. For inline and delimiter-based formulae, enable Goldmark’s passthrough extension and set the delimiter pairs appropriate for the site. The included oink.pgsty.com config shows square-bracket, double-dollar, and parenthesis pairs.

Enable the passthrough extension

The relevant YAML structure is:

YAML
markup:
  goldmark:
    extensions:
      passthrough:
        enable: true
        delimiters:
          block: []
          inline: []

Fill the arrays with Hugo’s documented delimiter pairs. Choose pairs that do not conflict with the site’s prose or code and apply the setting consistently in every build environment.

Add the passthrough render hook

For delimiter-based math, create layouts/_markup/render-passthrough.html in the site:

GO-HTML-TEMPLATE
{{ partial "scripts/math.html" . }}

The hook can be scoped to a content type or section by placing it under the corresponding layout directory. A scoped hook avoids treating unrelated content as mathematical passthrough.

Chemical equations and physical units

Hugo’s embedded KaTeX supports the mhchem extension. Use chem code blocks for chemical equations. The same extension supports physical units. See the mhchem manual for its equation and unit syntax.

Diagrams with Mermaid

Mermaid turns a text definition into a diagram in the browser. Use a mermaid code block:

MARKDOWN
```mermaid
flowchart LR
  Source --> Hugo --> Static
```
flowchart LR
  Source --> Hugo --> Static

The theme detects the block, publishes its pinned local Mermaid runtime, and loads it once on that page. Pages without Mermaid do not load the runtime.

Site-wide Mermaid settings live under params.mermaid:

YAML
params:
  mermaid:
    theme: neutral
    flowchart:
      diagramPadding: 6

Per-diagram front matter can override supported Mermaid settings. Keep diagram text readable in source, test both color modes, and provide surrounding prose for information that must remain accessible when a diagram cannot render.

UML diagrams with PlantUML

PlantUML supports sequence, use-case, class, state, and other UML-oriented diagrams. A plantuml block contains the source:

MARKDOWN
```plantuml
actor Reader
participant Browser
participant "PlantUML endpoint" as Server
Reader -> Browser: Open page
Browser -> Server: Request encoded diagram
Server --> Browser: SVG
```

PlantUML requires a renderer endpoint. Enable it only with an approved local or explicit remote service:

YAML
params:
  plantuml:
    enable: true
    theme: default
    svg_image_url: https://plantuml.internal.example/plantuml/svg/
    svg: false

The endpoint receives encoded diagram source from the browser. Review its confidentiality, availability, CSP, and offline implications. For an air-gapped site, use an internal endpoint or commit pre-rendered images; do not point the default configuration at a public demo server.

Mind-map support with Markmap

Markmap converts a Markdown outline into an interactive mind map:

MARKDOWN
```markmap
# Local-first
## Build
- Hugo Extended
## Browser
- Local scripts
- Local fonts
```
# Local-first
## Build
- Hugo Extended
## Browser
- Local scripts
- Local fonts

Enable the feature globally when desired:

YAML
params:
  markmap:
    enable: true

The runtime is pinned and served locally. Keep the underlying outline useful and avoid relying on pointer-only interactions.

Diagrams with Diagrams.net

Diagrams.net (draw.io) can export SVG and PNG files that retain an embedded copy of their editable diagram. OINK can detect those images and show an Edit action when an editor endpoint is explicitly configured.

YAML
params:
  drawio:
    enable: true
    drawio_server: https://drawio.internal.example/

Export with Include a copy of my diagram enabled. The page can display the exported image offline, but opening the editor requires the configured service. Saving in the editor downloads an updated file to the browser; it does not write directly to the documentation repository.

Treat a public Diagrams.net endpoint as an online integration. If editing must stay inside an organization, deploy an approved self-hosted editor and set drawio_server to it.

Resource and authoring checklist

  • Use text-based diagrams when reviewable diffs are valuable.
  • Provide alt text or adjacent prose for essential meaning.
  • Test light, dark, mobile, print, and reduced-motion behavior.
  • Keep local runtimes pinned in VENDOR.json and load them only when used.
  • Never include secrets in diagram source sent to a service endpoint.
  • Use pre-rendered output when an online renderer is unacceptable.
  • Verify all asset and endpoint URLs under a subpath baseURL.

10 - Apache ECharts

Build responsive, local-first charts from structured JSON or YAML.

The echarts shortcode renders an Apache ECharts options object with the versioned runtime bundled by Oink. Hugo parses JSON or YAML at build time, serializes the result into the page, and loads ECharts only on pages that use the component.

Use ECharts for quantitative charts whose axes, encodings, tooltips, or series need more control than a diagram or table provides. Keep a nearby textual summary so the conclusion does not depend on color, pointer interaction, or JavaScript.

Quick start

GO-HTML-TEMPLATE
{{< echarts height="300px" >}}
xAxis:
  type: category
  data: [Draft, Review, Publish]
yAxis:
  type: value
series:
  - type: bar
    data: [12, 9, 4]
{{< /echarts >}}

The example shows 12 draft pages, nine pages in review, and four pages ready to publish.

How Oink loads a chart

The shortcode creates a unique chart container and stores the parsed options in an application/json element. The page includes the local ECharts runtime and Oink initializer once, even when it contains several charts.

If theme is not set, Oink initializes the chart for the current site color mode and redraws it when the reader changes modes. A ResizeObserver resizes the chart with its container. Setting an explicit ECharts theme opts out of automatic site-theme switching for that chart.

Shortcode parameters

Parameter Default Behavior
height 400px Accepts a nonnegative number with px, rem, em, vh, vw, or %
theme unset Uses a named ECharts theme; when unset, follows the site’s light or dark color mode
full false Set to true to remove Oink’s normal content-width clamp

Invalid height values fail the Hugo build. The shortcode body must decode to an ECharts options object; malformed JSON or YAML also fails at build time instead of creating a blank chart silently.

Choose a guide

scatter plots, legends, and visual encodings.

  • Callbacks and trusted code: explains formatter functions, data-dependent styles, the $fn:name bridge, and its security boundary.

Start with declarative JSON or YAML. Add JavaScript callbacks only when the ECharts option cannot be expressed as data.

Authoring checklist

  • State the chart’s conclusion and data scope in prose.
  • Label axes, units, series, and time ranges explicitly.
  • Do not use color as the only way to distinguish important values.
  • Keep legends and tooltips readable in both site color modes.
  • Test the chart at narrow widths and with long translated labels.
  • Prefer a shared dataset when several series use the same records.
  • Record the data source and observation date for nonillustrative data.
  • Avoid animation when it does not help comprehension, and respect reduced motion for custom effects.

Further reference

OINK documents its wrapper and delivery behavior; the full options schema belongs to Apache ECharts. Use the ECharts concepts handbook, dataset guide, and option reference for chart-specific settings. The theme’s VENDOR.json records the exact runtime version and license shipped by a release.

11 - Infographics with AntV

Turn concise declarative data into local SVG infographics.

The infographic shortcode renders the AntV Infographic DSL with the versioned runtime bundled by Oink. Use it for processes, timelines, cycles, funnels, roadmaps, and compact visual summaries where a statistical chart would be too literal.

The DSL is serialized as data, not inserted as arbitrary HTML or executable code. The browser runtime turns it into SVG and loads only on pages that use the shortcode.

Quick start

GO-HTML-TEMPLATE
{{< infographic >}}
infographic list-row-simple-horizontal-arrow
data
  title Documentation workflow
  items
    - label Draft
      desc Write the first version
    - label Review
      desc Check facts and language
    - label Publish
      desc Build and verify the site
{{< /infographic >}}

The same three steps appear below. Drafting creates the first version, review checks facts and language, and publication builds and verifies the site.

Syntax anatomy

An infographic normally contains:

  1. infographic TEMPLATE, which selects a built-in AntV template;
  2. a data block with an optional title and desc;
  3. an items list with label, desc, optional value, and optional nested children fields;
  4. an optional theme block for a built-in theme or explicit colors.

Indentation defines structure. Keep labels short, use descriptions for context, and choose a template whose visual relationship matches the prose. A decorative sequence is not a substitute for an actual hierarchy or comparison.

Shortcode parameters

Parameter Default Behavior
height auto Accepts auto or a nonnegative number with px, rem, em, vh, vw, or %
full false Set to true to remove Oink’s normal content-width clamp

Invalid height values and an empty DSL body fail the Hugo build. DSL schema or template errors are reported by the browser runtime in the infographic container.

AntV themes belong to the DSL rather than the shortcode parameters. They do not automatically follow Oink’s site color mode, so verify foreground, background, and surrounding-page contrast in both modes.

Choose a guide

  • Processes, timelines, and cycles: demonstrates three common ways to explain a sequence.
  • Layouts, funnels, and themes: demonstrates grids, narrowing stages, template selection, and a built-in hand-drawn theme.

The AntV package contains many templates. Start with the smallest visual form that clarifies the relationship, not the most decorative form available.

Authoring and accessibility

  • Summarize the same conclusion in ordinary text before or after the graphic.
  • Keep the reading order meaningful and labels concise.
  • Do not use color or shape as the only carrier of status.
  • Check long translated labels, narrow screens, printing, and both site color modes.
  • Avoid remote image or icon identifiers in a local-first page unless their network and license boundary has been reviewed explicitly.
  • Record the source and date when values are not illustrative.

SVG improves visual fidelity, but it does not guarantee that every template exposes the same semantic structure as native headings, lists, and tables. Essential instructions must remain available in adjacent prose.

Further reference

OINK documents its shortcode and delivery boundary. For the full DSL, template gallery, and theme model, use the AntV Infographic documentation, gallery, and source repository. The Oink theme’s VENDOR.json records the exact bundled version, checksum, and MIT license file.