Code Blocks
A code block is an ordinary Markdown fence. Highlighting is done at build time
by Chroma, which Hugo embeds; there is no highlighter in the browser. Use it for
commands, configuration snippets and source. The {…} attributes on the fence’s
info line decide the title bar, copy behaviour, line numbers and line anchors.
Diagram-style fences (mermaid, echarts, filetree and friends) never take
this path — each has its own render hook.
Shortest form
A fence with no attributes still gets the full shell and a copy button. Without
a title there is no empty bar: the copy button floats at the top right and
appears on hover or when focus enters the block, and is always visible on touch
devices. The shell does not display the language; the lexer name goes into
data-language for stylesheets and tests.
The language tag is simply Chroma’s lexer name. A diff fence renders a patch
with Chroma’s added / removed line styling, no extra component involved:
Filename titles
title gives the block a visible title bar, usually a filename or a path. It
also becomes the block’s accessible name.
filename is a historical alias of title; writing both fails the build.
Line numbers, start line and highlighting
lineNos takes inline (numbers in the same column as the code) or table
(numbers in their own column, selectable on their own and never copied).
lineNoStart changes the first displayed number. hl_lines marks lines to
emphasize, counted from 1 over the source lines inside the fence, independent of
lineNoStart.
lineNos="table" puts the numbers in a separate column — in both modes the
copy button strips them:
tabWidth decides how many spaces a tab expands to and, like style, is handed
straight to Chroma. This site uses class-based Chroma palettes (one for light,
one for dark), so style only takes effect when Hugo is switched back to inline
style mode.
Wrapping long lines
wrap=true changes display only: the source is unchanged and so is the text you
copy. Without it, long lines scroll horizontally.
wrap=true cannot coexist with table line numbers: the number column and the
code column are two table cells, and wrapping puts them out of step. Writing
both fails the build, and the error suggests lineNos="inline" or dropping the
wrap.
Folding long code
collapse=N shows the first N lines with a “show all N lines” button at the
bottom. The server emits the complete code; folding is a visual clip applied
after the browser measures where line N ends. Without JavaScript, in a screen
reader, and in print, the code is complete.
When the block is no longer than collapse, no button appears. Wrapping and
folding work together: folding measures the bottom edge of the Nth source line
node, so a wrapped line is never cut in half.
What gets copied
By default the whole source is copied. Terminal sessions — the console and
shell-session lexers — copy the commands only: prompted lines survive, the
prompts themselves and the output lines are dropped. Copying the block below
gives two commands, with no $ and no output.
To copy prompts and output too, write copy="all". Using copy="command" on an
ordinary lexer such as bash or sh fails the build, because those cannot tell
prompt, command and output apart. For multi-line commands, write the
continuation prompt (usually >) on the continuation lines, or they are treated
as output and excluded.
When a session-lexer block contains no prompt at all, the copy button reports failure: the icon turns to its error state, an error is logged to the console, and the clipboard is untouched. It never falls back to copying everything.
copy=false removes the copy button from one block — useful for a
counter-example nobody should paste:
To turn copying off site-wide use params.ui.code_copy: false, which overrides
whatever a block writes in copy (see
Configuration). The copy button
is icon-only; success and failure swap the icon and announce a localized status.
What is copied keeps indentation, blank lines and Unicode, drops line numbers,
and ends with exactly one newline.
Line links and stable IDs
Turning “see line 3” into a link takes two steps: give the fence an explicit
id, then enable anchorLineNos=true. The line numbers become anchor links of
the form #<id>-<line>.
Jump to line 4.
Without an id the theme still generates one that is unique on the page, but it
depends on where the fence sits in the page — insert another fence above it and
the ID changes. Only an author-written id is a permanent link. IDs must not
contain whitespace or control characters, and must not collide with any other
viewport, tab, panel, title or line-anchor ID on the page; a collision fails the
build.
Numbered examples
In a book or a long manual, number the snippets: num plus caption turns the
fence into a Book “example” target that xref can reference and that appears in
the book-wide list of examples. The number is written by the author — the theme
never counts — and id defaults to eg-<num>.
See Example 4-1.
num and caption must appear together; one without the other fails the build.
num is mutually exclusive with the tab attribute tab. For numbering and
indexing figures, tables and equations, see
publishing books.
A set of fences as tabs
Consecutive fences carrying tab are assembled into one tab set in the browser.
A group on the first fence makes the set shareable, synchronized and
remembered.
The complete rules — group syntax, URL hash, cross-group synchronization, tabs in running text — are on the Tabs page.
Things that bite
- Showing a shortcode in the docs: a fence does not stop Hugo from parsing, so a
{{< tabs >}}written inside a code block still executes. To display it verbatim, add a comment marker inside each delimiter —{{</* tabs */>}}, and{{%/* steps */%}}for the percent form. Every shortcode shown on this page is written that way. - Fences inside fences: four backticks outside, three inside — every “Source” block on this page does it. Add another backtick when the inner block has fences of its own.
- Attributes go on the info line: a fence’s attributes follow the language on the opening line. Only tables and images take their attributes on the line below. Put them on the next line and you get a visible line of braces.
- Unknown attributes fail rather than being ignored, and the error lists the
allowed names.
style,srcdocandon*are rejected; thedata-td-code*prefix plusdata-language,data-line-countanddata-collapse-linesare reserved by the theme and fail the build too. - Fences in list items: indent them to line up with the item’s content (three
spaces after
1.), or the fence leaves the list.
Output
| Output | Shape |
|---|---|
| HTML | A <div class="td-code"> shell around Chroma’s .highlight/.chroma; copy and fold buttons ship hidden and appear once the script confirms it can run |
| Complete code; copy, fold and the fade are removed; long blocks may break across pages; the title bar stays | |
| Markdown | The source fence, {…} attributes and all, emitted as written |
| RSS | A static code block with no buttons |
A page with no copy or fold control never loads code-block.js; print, Markdown
and RSS never load it.
Parameter reference
Inside the {…} after the language on the opening line, OINK’s own attributes:
tab, ,- Tab label, see Tabs; mutually exclusive with
num
title, filename and label already give the block an accessible name and
role="group". Any of them together with aria-label, aria-labelledby or
role fails the build; those three attributes pass through only when the block
has neither a title nor a label.
The same line also takes Chroma options, which the theme hands to Hugo unchanged:
Limits
- No swapping the highlighter: there is no Shiki, no Twoslash, no
browser-side highlighting and no runnable playground. For patches use a
difffence — Chroma’s.gi/.gdare the added / removed line styles. copy="command"recognizes session lexers only: on any other language it is a build error, never a silent fallback to copying everything.- A generated ID is not a permanent link: write
idwhen you intend to share one. mermaid,math,chem,markmap,plantuml,echarts,infographic,checksums,filetreeandgalleryare not code blocks: each has its own render hook, no shell around it and no copy button.
Related
- Tabs — the full rules for assembling adjacent fences
- Include — pull a real file from the repository in as a code block
- Publishing books — numbered examples, cross references, the list of examples
- Print — what long code looks like on paper