` |
| Rule | `---` | ` ` |
| Fence | ```` ```js[Title]{lines} ```` … ```` ``` ```` | ``; with a title, a listing |
| Display math | `$$` … `$$ {#eq-id}` | `div.t-eq`; numbered when it has an id |
| Table | `| a | b |`, then `|---|---|` | `` |
| Block | `:::name[Title]{attrs}` … `:::` | the element the name denotes, else `div.name` |
| Cell | `+++` inside a block | `div.t-cell`, in a grid |
| Leaf | `::name[content]{attrs}`, alone on a line | the element the name denotes, else `div.name` |
| Inline element | `:name[content]{attrs}` | the element the name denotes, else `span.name` |
| Span | `[text]{.class}` | `` |
| Attributes | `{#id .class key=value}` | `id`, `class` and other attributes |
| Attribute line | `{.lead}` alone on the line before a block | the attributes, on that block |
| Reference | `@id`, `@id{ref=title}` | a link whose text comes from the target: "Theorem 1", "(2)", a title |
| Footnote | `[^a]` in the text, `[^a]: …` anywhere | a numbered note at the end |
| Metadata | `:::meta` with `key: value` lines | ``, ``, ` ` |
| Macros | `:::macros` with `\gdef` lines | TeX macros shared by every formula |
| Raw HTML | a block tag on its own line; `` and other inline tags in text; a ```` ```=html ```` fence | the HTML, as written |
| Escape | `\` before any ASCII punctuation | the character itself |
**Reference:** [Syntax: blocks](syntax-blocks.html#top) and [Syntax: inline](syntax-inline.html#top).
## Paragraphs and line breaks {#paragraphs}
A paragraph is a run of lines that start nothing else. A blank line ends it. The lines of a paragraph are joined: a single line break in the source is a soft break, which the browser shows as a space.
```tern {.live}
A paragraph can span
several lines in the source.
A blank line starts the next one.
```
To force a line break, end the line with a backslash. In HTML it is a ` `.
```tern {.live}
Roses are red,\
violets are blue.
```
- **Leading spaces** on a paragraph line are dropped, so you can indent continuation lines.
- **A backslash on the last line** of a paragraph is a literal backslash: there is nothing after it to break to.
- **Two trailing spaces** do nothing (rule 3). Use the backslash.
`\\` at the end of a line is an escaped backslash, not a break. Tern prints one backslash and tells you, in case you meant a line break, as in LaTeX:
```tern {.live expect="latex.linebreak"}
In LaTeX this is a break,\\
in Tern it is a backslash.
```
**Reference:** [Paragraphs](syntax-blocks.html#paragraph), [hard breaks](syntax-inline.html#hard-break), [`latex.linebreak`](diagnostics.html#latex-linebreak).
## Emphasis, code and highlight {#emphasis}
| You write | You get |
|---|---|
| `*emphasis*` | *emphasis*, `` |
| `**strong**` | **strong**, `` |
| `***both***` | ***both*** |
| `~~struck~~` | ~~struck~~, `` |
| `==highlight==` | ==highlight==, `` |
| `` `code` `` | `code`, `` |
```tern {.live}
Use *emphasis*, **strong**, ***both***, ~~strikethrough~~ and ==highlight==,
or `code` for anything typed literally.
```
### Rules worth knowing {#emphasis-rules}
- **Only the asterisk** makes emphasis. Underscores are always text, so `snake_case`, `__init__` and URLs with underscores need no escaping.
- **Spaces around** an asterisk make it text: `2 * 3 * 4` stays as typed.
- **`~~` and `==`** take exactly two characters, and they do not open or close when glued to an ASCII letter or digit on the outside. `a==b` and `x == y` are text.
```tern {.live}
snake_case, __init__ and _private_ stay as typed.
2 * 3 * 4 is arithmetic, a==b and x == y are comparisons,
but (==this==) is highlighted.
```
Highlight and strikethrough work inside words of languages without spaces, because only ASCII letters and digits count as glue:
```tern {.live}
これは==重要==です。
```
### Code spans {#code-spans}
A code span shows its content exactly, with nothing inside it interpreted. To put a backtick inside, wrap the span in a longer run of backticks; a space just inside each end is removed, so a span can start or end with a backtick.
```tern {.live}
`a < b && c > d`, ``a`b``, and a lone backtick: `` ` ``.
```
### Escapes {#escapes}
A backslash before any ASCII punctuation character makes that character literal: `\*`, `\$`, `\@`, `\[`, `\#`, `\\`. A backslash before anything else is just a backslash.
```tern {.live}
\*not emphasis\*, a price of \$5, an \@handle, \[not a link\](x),
and a backslash: \\.
```
At the start of a line, an escape stops a block from starting:
```tern {.live}
\# Not a heading.
\- Not a list item.
1\. Not a numbered item.
\> Not a quote.
\::: not a block, \::not-a-leaf
\$$ not display math
\{.not-attributes}
\+++ \--- \[^1]
```
Each section below ends its rules with the escape for its construct, when it has one.
**Reference:** [emphasis](syntax-inline.html#emphasis), [strikethrough](syntax-inline.html#strikethrough), [highlight](syntax-inline.html#highlight), [code spans](syntax-inline.html#code-span), [escapes](syntax-inline.html#escapes).
## Headings and their ids {#headings}
One to six `#`, a space, and the heading's text. A heading is always one line.
```tern {.live}
# A level-one heading
## Level two
### Level three
```
### Ids {#heading-ids}
Every heading gets an `id`, so you can link to it. When you write none, Tern makes one from the heading's text: lower-cased, with runs of spaces and punctuation turned into `-`, and anything before the first letter dropped. Letters of every script are kept.
```tern {.live}
## Kernel and image
## Überblick
## 2. Results
## 日本語
```
To choose the id yourself, put `{#id}` at the end of the line. Classes and other attributes can go in the same braces:
```tern {.live}
## Kernel and image {#kernel .wide}
```
- **Collisions.** When a made-up id is already taken, the next heading gets `-2`, `-3` and so on, silently. An id you wrote yourself always wins over a made-up one.
- **Choose ids for anything you link to.** A made-up id changes when you reword the heading; one you wrote does not.
```tern {.live}
## Setup
## Setup
## Setup
```
### What is not a heading {#not-a-heading}
- `#hashtag` and `#1 priority`: the `#` must be followed by a space.
- A line underlined with `===` or `---`: Tern has no underlined headings. `---` after a paragraph is a rule.
- A closing run of `#` is part of the text: `# C# #` keeps both.
```tern {.live}
#hashtag stays text.
# C# #
Title
===
```
**Reference:** [headings](syntax-blocks.html#heading), [ids](elements.html#ids).
## Links and images {#links}
A link is the text in brackets, then the destination in parentheses, with an optional title in quotes.
```tern {.live}
Read [the guide](guide.html), or [the spec](https://example.com/spec "Normative").
```
- **Spaces in a destination**: wrap it in angle brackets, `[my file]()`. Non-ASCII characters are percent-encoded for you.
- **Attributes** go in braces right after the link: `[Download](notes.pdf){.button download}`.
- **No reference-style links.** `[text][label]` is plain text. Write the destination inline.
```tern {.live}
[my file](), [café](café.html), [Download](notes.pdf){.button download}.
```
### Autolinks {#autolinks}
A URL in angle brackets becomes a link, and so does an e-mail address. A bare `http://` or `https://` URL is linked too. It stops at a space or a bracket, and trailing punctuation is left out, so a URL can end a sentence.
```tern {.live}
, , and a bare https://example.com/docs.
Parentheses that belong to it stay: https://en.wikipedia.org/wiki/Tern_(bird).
```
To keep a URL as text, escape its colon: `https\://example.com`.
### Links inside the note {#fragment-links}
`[text](#id)` links to an id in the same note. Tern checks it: a fragment that names no id gets a warning, and the link stays a link.
```tern {.live expect="ref.dangling"}
## Setup {#setup}
See [the setup](#setup), and [nothing](#nowhere).
```
For a link whose text comes from its target, such as "Theorem 2", use a reference, `@id`, covered in [References](#references).
### Images {#images}
An image is a link with `!` in front. The bracket text is the alternative text, read aloud by screen readers and shown when the image cannot load.
```tern {.live}
{width=320}
A feather {width=24} can sit inside a sentence.
```
- **Paths** are relative to the note, as in any HTML page.
- **Attributes** set the size and anything else: `{width=50%}`, `{loading=lazy}`.
- **Empty brackets** give an empty `alt`, right for a purely decorative image.
- **`alt=`** wins over the bracket text when you give both: `{alt="A plane and a line"}`.
- **An image with an id becomes a figure**, with the bracket text as its caption. See [Figures](#figures).
**Reference:** [links](syntax-inline.html#links), [images](syntax-inline.html#images), [autolinks](syntax-inline.html#autolinks).
## Lists and tasks {#lists}
Bullet items start with `-`, numbered items with a number and `.` or `)`. Indent a nested list under the text of its item.
```tern {.live}
- Milk
- Bread
- white
- rye
- Eggs
1. Preheat the oven.
2. Mix.
3. Bake.
```
- **Start number.** A numbered list keeps its first number: `7.` starts at 7.
- **One list or two.** Changing the bullet character (`-`, `*`, `+`) or the delimiter (`.` or `)`) starts a new list.
- **Tight or loose.** A blank line between items makes the list loose: each item becomes a paragraph, with more space. (Below, the `*` bullets start a second list, so the first one stays tight.)
```tern {.live}
7. seven
8. eight
- a tight
- list
* a loose
* list
```
### Tasks {#tasks}
An item that starts with `[ ]` or `[x]` is a task: it gets a checkbox, ticked or not, which the reader cannot change.
```tern {.live}
- [x] Motions
- [ ] Operators
- [x] `d`, `c`, `y`
- [ ] text objects
- [ ]
```
### Blocks inside items {#list-blocks}
Anything can go inside an item: paragraphs, fences, tables, math, `:::` blocks. Indent it to where the item's text starts. Here the blank lines between the parts make the list loose.
````tern {.live}
1. Install the tools:
```sh
npm install
```
2. Read the note:
:::aside
Inside the second item.
:::
````
### Numbers in prose {#list-prose}
A numbered item can interrupt a paragraph only when it is numbered 1, so a wrapped line that starts with a year stays prose. After a blank line, though, a line starting `2019.` is a list item; escape the dot to keep it text.
```tern {.live}
The project started in
2019. It grew from there.
2019\. was the year it started.
```
**Reference:** [lists](syntax-blocks.html#lists).
## Quotes {#quotes}
A quote is a run of lines starting with `>` and a space. Lines that merely continue a paragraph may leave out the `>`. Anything can go inside a quote, including lists and blocks.
```tern {.live}
> The best way to predict the future
is to invent it.
>
> - a list inside
> - the quote
```
- **Nesting.** `> >` starts a quote inside a quote.
- **`>` needs a space** (or the end of the line) to open a quote, so `>5 people` and `>= 3` are text.
- **Literally:** `\>` at the start of a line.
```tern {.live}
> :::aside
> A block inside a quote.
> :::
>5 people and >= 3 are text.
```
**Reference:** [blockquotes](syntax-blocks.html#blockquote).
## Code fences {#code}
A fence is three backticks, an optional language, the code, and three backticks. The code is shown exactly as written.
````tern {.live}
```python
def greet(name):
return f"Hello, {name}!"
```
````
The language becomes the class `language-python` on ``, which syntax highlighters look for. Tern itself does not colour code. To start a line with three backticks as text, escape the first one: ```` \``` ````.
### Line numbers and highlights {#code-lines}
Three settings go in braces after the language:
| Setting | Effect |
|---|---|
| `lines` | numbers every line |
| `start=10` | starts the numbering at 10 |
| `hl=2,4-5` | highlights those lines, counted as displayed |
````tern {.live}
```js {lines start=10 hl=11}
const a = 1;
const b = 2;
console.log(a + b);
```
````
Other attributes, such as a class, go in the same braces and land on the `` (on the ``, for a titled fence).
### Titled fences: listings {#listings}
A title in brackets after the language turns the fence into a listing: a `` with the title as its caption. Give it an id to link to it.
````tern {.live}
```js[A lazy Fibonacci generator]{#lst-fib}
function* fib() {
let [a, b] = [0, 1];
for (;;) { yield a; [a, b] = [b, a + b]; }
}
```
@lst-fib never ends; take what you need.
````
With no vocabulary, the reference shows the title. A vocabulary that declares `code` with a counter and a label numbers listings, and the reference reads "Listing 1". Here is the same source with the demo vocabulary:
````tern {.live schema=demo}
```js[A lazy Fibonacci generator]{#lst-fib}
function* fib() {
let [a, b] = [0, 1];
for (;;) { yield a; [a, b] = [b, a + b]; }
}
```
@lst-fib never ends; take what you need.
````
### Diagrams {#diagrams}
With the Mermaid add-on, a fence in the language `mermaid` is drawn as a diagram, in the theme's colours: flowcharts, sequence diagrams, Gantt charts and the rest of Mermaid's diagrams.
```html
```
````tern
```mermaid
flowchart LR
A[Write] --> B[Check] --> C[Publish]
```
````
Put it in a `:::figure` to give it a caption and a number. The [Add-ons](addons.html#mermaid) page has the colours, the options and how to use it offline.
### Fences inside fences {#fence-in-fence}
Everything inside a fence is code, including `:::`, `$$` and `#` lines. To show a fence in a fence, make the outer one longer:
`````tern {.live}
````md
```js
x = 1
```
````
`````
### When a fence goes wrong {#fence-problems}
A fence that is never closed runs to the end of the note, or of the list item or quote it is in, and is reported as an error:
````tern {.live expect="block.unclosed-fence"}
```js
let x = 1;
The rest of the note became code.
````
The info after the backticks is a language, then a `[Title]`, then a `{…}` group, in that order. Anything else is kept in `data-meta` on the ``, with a warning:
````tern {.live expect="fence.info-junk"}
```js extra words
x = 1;
```
````
**Reference:** [fences](syntax-blocks.html#fence), [`block.unclosed-fence`](diagnostics.html#block-unclosed-fence), [`fence.info-junk`](diagnostics.html#fence-info-junk).
## Math {#math}
Math is written in TeX between dollars. The engine parses it but renders nothing itself: each formula is left as its TeX, the way a code fence stays plain without [`code.js`](addons.html#code). To typeset it, load a [math add-on](addons.html#katex) in `data-use` — `addons/katex.js` for KaTeX, or `addons/mathml.js` for native MathML. Inside math, everything is TeX: Tern's marks mean nothing there (rule 4).
### Inline math {#inline-math}
```tern {.live}
The sum $\sum_{i=1}^{n} x_i^*$ adds every optimum $x_i^*$,
and $e^{i\pi} + 1 = 0$ is famous.
```
### Dollars that are prices {#prices}
Prose is full of dollar signs, so Tern only treats a pair of dollars as math when it looks like math:
- the opening `$` is followed by a non-space;
- the closing `$` follows a non-space, and is not followed by a digit;
- the two are at most one line break apart;
- the first `$` after the opener decides: if it cannot close, the opener is text.
So ordinary prices need no escaping. The reference lists a few more cases, such as a `$` inside parentheses.
```tern {.live}
It costs $5, or $10 at peak hours. Tickets are $5–$10.
The $0$th, $1$st and $n$th terms are math.
```
When a price and a formula share a sentence, the first dollar may pair with the wrong one. Tern warns when a "formula" starts with a digit and holds words. Escape the price with `\$`:
```tern {.live expect="math.suspect-price"}
It costs $5 then x$ more.
It costs \$5, then $x$ more.
```
### Verbatim math {#verbatim-math}
When TeX itself contains a dollar, or an interval such as `]0,1[` that the dollar rules turn down, write `` $`…` ``: a dollar followed by a backtick span. It is always math.
```tern {.live expect="math.bracket"}
The interval $`]0,1[` is open, and $`\$5 + \$10` is TeX's dollar.
$]0,1[$ is not math, and Tern says how to write it.
```
### Display math {#display-math}
A formula on its own lines goes between two `$$` lines. A short one can stay on one line.
```tern {.live}
$$
\dim V = \dim \ker T + \dim \operatorname{im} T.
$$
$$ e^{i\pi} + 1 = 0 $$
```
- **No blank lines** inside: TeX forbids them, and Tern uses that to recover from a forgotten `$$`.
- **`$$` in the middle of a line** is text. For a large formula inside a sentence, write `$\displaystyle …$`.
- **Literally:** `\$` for a dollar anywhere, `\$$` at the start of a line.
A blank line, a heading, a fence or a `:::` line ends a display formula that was never closed. The source stays visible in red, the error names the line, and nothing after it is swallowed:
```tern {.live expect="math.unclosed"}
$$
a^2 + b^2 = c^2
## The next heading survives
```
### Numbered equations {#equations}
Give a display formula an id, after its closing `$$`, and it is numbered. `@id` refers to it as "(1)".
```tern {.live}
$$
\dim V = \dim \ker T + \dim \operatorname{im} T.
$$ {#eq-rn}
$$ e^{i\pi} + 1 = 0 $$ {#eq-euler}
By @eq-rn and @eq-euler, …
```
- **Only formulas with an id** are numbered, in document order. Inline math is never numbered.
- **Attributes go after the closer.** On the opening `$$` line, braces are TeX: below, `{.wide}` is typeset as part of the formula, and Tern reports an error.
```tern {.live expect="math.opener-tail"}
$$ {.wide}
x = 1
$$
```
### Macros {#macros}
A `:::macros` block defines TeX macros for every formula in the note. Its body is TeX, read as written.
```tern {.live}
:::macros
\gdef\R{\mathbb{R}}
\gdef\norm#1{\lVert #1 \rVert}
:::
For every $x \in \R^n$, $\norm{x} \ge 0$.
```
All macro blocks are read before any formula is typeset, so a macro works anywhere in the note. The block itself is hidden.
**Reference:** [inline math](syntax-inline.html#inline-math), [verbatim math](syntax-inline.html#verbatim-math), [display math](syntax-blocks.html#display-math), [macros](syntax-blocks.html#raw-body), [numbering](elements.html#numbering).
## Tables {#tables}
A table is a header row, a delimiter row, and body rows. Every row starts with `|`.
```tern {.live}
| Phase | Weeks | Owner |
|---|--:|:-:|
| Engine | 4 | O.C. |
| Runtime | 3 | O.C. |
```
- **Alignment** comes from colons in the delimiter row: `:--` left, `--:` right, `:-:` centred.
- **A trailing `|`** is optional.
- **Cells** hold inline content: emphasis, code, math, links, elements.
- **Missing cells** are left empty. **Extra cells** are kept, with a warning.
### Pipes in cells {#table-pipes}
A pipe inside code or math does not split a cell. Anywhere else, escape it as `\|`.
```tern {.live}
| Input | Meaning |
|---|---|
| `a|b` | a pipe in code |
| $|x|$ | absolute value |
| either \| or | an escaped pipe |
```
### Long rows {#table-continuation}
A row that ends with a single `\` continues on the next line, after a line break. Use it for long cells.
```tern {.live}
| Phase | Exit criterion |
|---|---|
| P3 | smoke tests green;\
no math task over 50 ms |
```
### Attributes and captions {#table-captions}
An attribute line before a table puts attributes on ` `. To give a table a caption, wrap it in `:::table[Caption]`; the block and the table merge into one `` with a ``.
```tern {.live}
:::table[Phases and exit criteria]{#tbl-phases .wide}
| Phase | Exit |
|---|---|
| P0 | every rule has a case |
:::
See @tbl-phases.
```
With a vocabulary that gives `table` a counter, the caption gains "Table 1" and the reference reads "Table 1" (demo vocabulary):
```tern {.live schema=demo}
:::table[Phases and exit criteria]{#tbl-phases}
| Phase | Exit |
|---|---|
| P0 | every rule has a case |
:::
See @tbl-phases.
```
### Tables without a header {#headerless}
A delimiter row at the start makes a table with no header:
```tern {.live}
|---|--:|
| apples | 3 |
| pears | 12 |
```
### Table mistakes {#table-problems}
A table must start with `|`. The Markdown habit of leaving out the outer pipes gives a paragraph, and a warning on the delimiter row:
```tern {.live expect="table.stray-delimiter"}
Keys | Action
---|---
w | next word
```
A row with more cells than the header keeps them, with a warning:
```tern {.live expect="table.extra-cell"}
| a | b |
|---|---|
| 1 | 2 | 3 |
```
**Reference:** [tables](syntax-blocks.html#tables), [table captions](elements.html#table-caption), [`table.stray-delimiter`](diagnostics.html#table-stray-delimiter).
## Blocks with `:::` {#blocks}
A block wraps any content in an element. It opens with three colons and a name, and closes with three colons.
```tern {.live}
:::aside
An aside can hold *anything*: paragraphs, lists, math, tables, other blocks.
:::
```
### Names become elements {#block-names}
The name decides the element (rule 6):
- **An HTML name** that may hold flow content becomes that element: `aside`, `section`, `article`, `details`, `figure`, `nav`, `header`, `footer`, `div` and others.
- **A lower-case name with a hyphen**, such as `:::tide-chart`, becomes that custom element.
- **Any other name** becomes a `div`, with the name as its class.
Every block gets the class `t-block`, its name as a class, and `data-t="name"`, so CSS and scripts can find it whatever its element.
```tern {.live}
:::section
A real ``.
:::
:::tide-chart
A custom element, ``.
:::
:::idea
``.
:::
```
To start a paragraph with three colons, escape the first: `\:::`. Names are case-sensitive: `:::Aside` is not `aside`, it is `div.Aside`. A few names are reserved and never produce their element, such as `script`, `style`, `main` and `body`; Tern says so when you use one.
### Titles {#block-titles}
A title goes in brackets right after the name. It can hold inline markup.
```tern {.live}
:::idea[Key *idea*]
A title becomes the block's first child, `div.t-title`.
:::
:::details[Show the answer]
The answer is 42.
:::
```
Some elements put the title in their own slot: a `details` block's title is its `
`, a `figure`'s is its ``, a `table`'s its ``, a `fieldset`'s its ``.
### Attributes on a block {#block-attributes}
Braces at the end of the opening line give the block an id, classes and attributes. A bare word sets a boolean attribute, such as `open` on `details`.
```tern {.live}
:::details[More]{#more .muted open}
Open from the start.
:::
```
### Nesting and closers {#closers}
Blocks nest. A bare `:::` closes the innermost open block. To close a block by name, write `:::/name`: it closes that block and everything still open inside it.
```tern {.live}
:::section
:::aside
Inside the aside.
:::
Back in the section.
:::/section
```
Use named closers for long blocks; they also let you see at a glance what is closing.
The number of colons is up to you. More colons can make an outer block stand out, as long as each closer repeats its opener's count:
```tern {.live}
::::section
:::aside
Inner.
:::
::::
```
The count never chooses which block closes: a bare closer always closes the innermost one. When its count differs from that block's opener, Tern points it out, and suggests a named closer:
```tern {.live expect="block.closer-count"}
:::section
:::aside
Inner.
::::
:::
```
### Block mistakes {#block-problems}
A block that is never closed runs to the end of the note, and the error points at its opener:
```tern {.live expect="block.unclosed"}
:::aside
This aside is never closed.
Everything below ends up inside it.
```
A named closer closes everything open inside the block it names. Blocks it closes that way are reported, each at its own opener:
```tern {.live expect="block.unclosed"}
:::section
:::aside
The aside's closer is missing.
:::/section
After the section.
```
The most common opener mistakes keep the block and show the stray text in red:
```tern {.live expect="block.opener-junk block.opener-junk"}
:::aside Danger
A title goes in brackets.
:::
:::aside[Danger] #warn .big
Attributes go in braces.
:::
```
A space after the colons, or a `:::` with nothing open, is text with a warning:
```tern {.live expect="block.spaced-name block.stray-closer"}
::: aside
is text.
:::
```
### Cells and grids {#cells}
Inside a block, a `+++` line starts a new cell. A block with cells becomes a grid, one column per cell. `cols` sets the column widths: a number of equal columns, or a list of relative widths.
```tern {.live}
:::row{cols="2 1"}
Left, twice as wide as the right.
+++
Right.
:::
```
- **Cell attributes** go after the `+++`: `+++ {.muted}`.
- **A first `+++`** right after the opener carries the first cell's attributes.
- **`cols` without cells** makes the block's own children the grid items, for example a block of cards.
- A list entry in `cols` that is not a number, such as `12rem`, is used as written.
- On narrow screens, every grid becomes one column.
- **Literally:** `\+++`.
```tern {.live}
:::row
+++ {.muted}
First cell.
+++ {.lead}
Second cell.
:::
:::cards{cols=3}
:::card[Parser]
Positions on every node.
:::
:::card[Runtime]
Renders in place.
:::
:::card[Editor]
A language server.
:::
:::/cards
```
A `+++` outside any block is text, with a warning:
```tern {.live expect="cell.orphan"}
+++
Not in a block.
```
### Raw bodies {#raw-bodies}
`{raw}` on a block keeps its body as plain text, for a script to read: a diagram description, data, a chart. Nothing in it is parsed.
```tern {.live}
:::mermaid{raw}
graph TD; A-->B
*not emphasis*
:::
```
`:::macros` and `:::meta` always have raw bodies.
### Choosing the element {#tag}
`{tag=…}` picks the element for one block, from the same list of HTML names:
```tern {.live}
:::note{tag=aside}
A note that is an ``.
:::
```
`tag=` works only on `:::`, `::` and `:` elements. On a span, link, heading or attribute line it is dropped, with a warning:
```tern {.live expect="tag.not-allowed"}
A [span]{tag=b} stays a span.
```
**Reference:** [containers](syntax-blocks.html#container), [closers](syntax-blocks.html#closer), [cells](syntax-blocks.html#cells), [names](elements.html#names), [allowlists](elements.html#allowlists), [title slots](elements.html#title-slots), [`block.unclosed`](diagnostics.html#block-unclosed).
## Leaves and inline elements {#elements}
### Leaves {#leaves}
A leaf is an element on one line: two colons, a name, optional content in brackets, optional attributes in braces. The line must hold nothing else. Leaves are how a note embeds media and web components without writing HTML. A video, for example:
```tern
::video{src=media/tide.mp4 poster=media/tide.jpg controls width=640}
```
becomes ` `. The same goes for an embedded page, a web component, or a name of your own:
```tern {.live}
::iframe{src=../examples/img/estuary-map.svg width=320 height=180 loading=lazy title="Estuary map"}
::tide-clock{station=leith units=m}
::byline[Lecture 7 · *O. Carrera*]
```
- **Media and embeds**: `video`, `audio`, `img`, `iframe`, `embed`, `object`, `picture`, `canvas`. An `::iframe` can show a map or a video player from another site, as in `::iframe{src="https://www.openstreetmap.org/export/embed.html?bbox=-3.2,55.95,-3.1,56.0" width=640 height=360}`.
- **Other HTML**: `hr`, `p`, `figcaption`, `summary`, and the block names.
- **A lower-case name with a hyphen** is a web component: `::tide-clock` is ``, ready for your `customElements.define`.
- **Anything else** is a `div` with the name as its class.
- **Literally:** `\::` at the start of a line.
A line that starts with `::name` but has more text after it is a paragraph, with a hint:
```tern {.live expect="leaf.demoted"}
::before and ::after are CSS pseudo-elements.
```
An element that cannot hold content, such as `hr`, puts what its brackets held after it, with a warning:
```tern {.live expect="leaf.void-content"}
::hr[The end]
```
### Inline elements {#inline-elements}
Inside text, `:name[content]` makes an element. The content can hold any inline markup, and braces after it hold attributes.
```tern {.live}
Press :kbd[Ctrl]+:kbd[S] to save.
:abbr[HTML]{title="HyperText Markup Language"} is a :dfn[markup language].
Ruby text: :ruby[漢:rt[kan]字:rt[ji]].
A :term[defined term] and a :my-badge[web component]{level=2}.
```
- **Inline names** become phrasing elements only: `kbd`, `abbr`, `dfn`, `cite`, `q`, `sub`, `sup`, `small`, `time`, `ruby`, `rt` and others. A name like `aside` is a `span.aside` here, because a block element cannot sit inside a paragraph.
- **The colon must not be glued** to a letter or digit before it. `press:kbd[S]` stays text, with a hint; so do times like `10:30[x]`.
- **Literally:** `\:kbd[x]`.
```tern {.live expect="inline.glued"}
Glued: press:kbd[S]. Spaced: press :kbd[S]. A time, 10:30[x], stays text.
```
For a subscript glued to a word, as in a chemical formula, use the HTML tag: `H2 O`.
### Spans {#spans}
Brackets followed directly by braces make a plain `` with those attributes. It is the way to put a class on a few words.
```tern {.live}
A [defined term]{.term} and an [answer]{.spoiler hidden}.
```
**Reference:** [leaves](syntax-blocks.html#leaf), [inline elements](syntax-inline.html#inline-element), [spans](syntax-inline.html#span), [allowlists](elements.html#allowlists).
## Attributes everywhere {#attributes}
One grammar, `{#id .class key=value}`, gives attributes to anything.
| Item | Means |
|---|---|
| `#id` | the `id` |
| `.class` | a class; several accumulate |
| `key=value` | an attribute; quote the value if it has spaces: `title="Two words"` |
| `key` alone | a boolean attribute, such as `open`, `controls` or `hidden` |
```tern {.live}
{#intro .lead data-level=1}
An introduction, with a [link](https://example.com){target=_blank rel=noopener},
`code`{.lang-js}, a formula $x${#ex}, **strong**{.key}, and a [span]{title="Two words"}.
```
### Where braces go {#attribute-places}
| Place | Example |
|---|---|
| right after a link, image, span, inline element or reference | `[t](u){.btn}`, `:kbd[C]{.big}` |
| right after a code span, formula or emphasis | `` `c`{.x} ``, `**b**{.y}` |
| at the end of a block's first line | `:::details[More]{open}`, ```` ```js {lines} ````, `$$ {#eq}`, `+++ {.muted}` |
| at the end of a heading | `## Kernel {#kernel}` |
| alone on the line before a block | `{.wide}` |
Everywhere else, braces are plain text: `the set {1, 2}`, `f{x}`.
In three of these places, braces count only when they hold an `#id`, a `.class` or a `key=value`: after a code span, formula or emphasis, at the end of a heading, and alone on a line. So a lone `{open}` or `{x}` there stays text, and so does prose such as `{1, 2}` on a line of its own.
```tern {.live}
`code`{hidden} keeps its braces as text, but `code`{.shown} takes the class.
{x}
```
### The attribute line {#attribute-line}
A line holding only `{…}` puts its attributes on the block that starts on the next line. It is how paragraphs, lists, tables, quotes and rules get attributes.
```tern {.live}
{.byline}
Lecture 7 · O. Carrera
{.checklist}
- one
- two
{.wide}
| a | b |
|---|---|
| 1 | 2 |
{.thin}
---
```
- **Several lines merge**: `{.a}` then `{.b}` gives both classes.
- **On a block** (`:::`), the line's classes come first, and the opener's other attributes win.
- **Nothing after it**: a blank line or the end of the note leaves the line as text, with a warning.
- **Literally:** `\{` at the start of the line.
```tern {.live expect="attributes.orphan"}
{.lead}
A blank line came between.
```
### Rules {#attribute-rules}
- **Last wins.** The last `#id` wins, and so does the last value of a repeated key. Classes accumulate.
- **Order in HTML**: `id`, then `class`, then the rest as written.
- **Quotes are literal.** Inside quotes nothing is special and there are no escapes. To put `"` in a value, use single quotes.
- **Reserved names.** `data-t` and the classes `tern` and `t-…` belong to Tern; they are dropped with a warning.
- **Reserved keys.** `tag`, `raw`, `cols` and `ref`, and on fences `lines`, `hl` and `start`, are settings for Tern and never reach the HTML. Each works only where it applies: `ref=` on a reference, `raw` on a block, `cols` and `tag=` on a `:::`, `::` or `:` element. Anywhere else it is dropped, with a warning.
```tern {.live expect="attr.malformed"}
A [span]{ref=title} is not a reference, so `ref=` is dropped.
```
A group that starts with `#` or `.` but does not parse stays text, with a warning at the first bad character:
```tern {.live expect="attr.malformed"}
{#intro!}
This paragraph gets no id.
```
**Reference:** [attributes](syntax-blocks.html#attributes), [the attribute line](syntax-blocks.html#attribute-line), [`attr.malformed`](diagnostics.html#attr-malformed).
## Figures {#figures}
A figure is an image, or anything else, with a caption. The quickest one is an image with an id, alone in its paragraph: the bracket text becomes the caption.
```tern {.live}
{#fig-osprey width=320 alt="An osprey in flight above grey water"}
```
- **The id makes the figure.** An image without an id, even alone, stays an image.
- **The caption is read once.** The image's `alt` is empty unless you give `alt=`, so a screen reader does not read the caption twice. Give `alt=` when the picture says more than the caption.
The id can also come from an attribute line before the image. With an attribute line, the id and classes go to the ``, and the image keeps its own attributes:
```tern {.live}
{#fig-crop .wide}
{width=160}
```
For anything else, a video, several images, an embedded map, use a `:::figure` block. Its title is the caption, and goes last, in a ``:
```tern {.live}
:::figure[A sketch map of the estuary.]{#fig-map}
::iframe{src=../examples/img/estuary-map.svg width=320 height=180 title="Estuary map"}
:::
```
A figure whose body is a single image puts the ` ` straight in the ``, without a paragraph around it.
### Numbered figures {#figure-numbers}
With no vocabulary, a figure has its caption and nothing more, and a reference to it shows the caption. A vocabulary that declares `figure` with a counter and a label numbers figures (demo vocabulary):
```tern {.live schema=demo}
{#fig-osprey width=320}
:::figure[The kernel and image of a rank-one map.]{#fig-kernel}
{width=240}
:::
Compare @fig-osprey with @fig-kernel.
```
**Reference:** [figures](elements.html#figures).
## References and numbering {#references}
`@id` links to the element with that id, and its text comes from the target. You never type "Theorem 3" or "(2)" yourself, so the numbers stay right when you reorder.
### What a reference says {#reference-text}
| Target | The reference reads |
|---|---|
| a heading | the heading's text |
| a numbered element (with a counter) | its label and number: "Theorem 1", "Figure 2" |
| a numbered equation | "(1)" |
| a titled element without a counter | its title |
| an element with a label but no counter or title | its label: "Proof" |
| anything else | the id |
With no vocabulary, only headings, equations and titles give a reference text:
```tern {.live}
## Kernel and image {#ki}
:::theorem[Rank–nullity]{#thm-rn}
$\dim V = \dim \ker T + \dim \operatorname{im} T$.
:::
$$ e^{i\pi} + 1 = 0 $$ {#eq-euler}
:::aside{#side}
An aside with no title.
:::
See @ki, @thm-rn, @eq-euler and @side.
```
### Why vocabulary matters {#why-vocabulary}
Tern's core knows no theorems, proofs or figures. A *vocabulary* tells it that `theorem` is a numbered `` labelled "Theorem", that `lemma` shares its counter, that a `proof` ends with ∎. The same source as above, with the demo vocabulary:
```tern {.live schema=demo}
:::theorem[Rank–nullity]{#thm-rn}
$\dim V = \dim \ker T + \dim \operatorname{im} T$.
:::
:::proof
Pick a basis of the kernel and extend it.
:::
:::lemma{#lem-inj}
$T$ is injective exactly when $\ker T = \{0\}$.
:::
See @thm-rn and @lem-inj.
```
- **Labels are real text.** "Theorem 1" is in the HTML, so it copies, prints, is found by search and is read by screen readers.
- **Counters are shared by name.** In the demo vocabulary, theorems, lemmas, propositions and corollaries count together, so the lemma above is Lemma 2.
- **Numbering is document-wide**, in the order the elements appear.
[Vocabulary and behaviour](#vocabulary) shows how to declare your own.
### Choosing the text {#ref-option}
`{ref=…}` after a reference picks which part of the target to show:
| `ref=` | Reads |
|---|---|
| `label` | Theorem 1 |
| `number` | 1 |
| `title` | Rank–nullity |
| `full` | Theorem 1 (Rank–nullity) |
```tern {.live schema=demo}
:::theorem[Rank–nullity]{#thm-rn}
…
:::
@thm-rn, @thm-rn{ref=number}, @thm-rn{ref=title}, @thm-rn{ref=full}.
```
For text of your own, use a link to the fragment: `[the main result](#thm-rn)`.
### Things that are not references {#not-references}
- **E-mail addresses** and handles glued to a word: `me@example.org`.
- **`@` before a digit or a space**: `@2024`, `@ home`.
- **`@name` with no such id** stays text, with a warning. Escape it if you meant a mention: `\@alice`.
```tern {.live expect="ref.dangling"}
Write to me@example.org, in @2024. Thanks to @alice and \@bob.
```
A reference runs on through letters, which matters in languages without spaces. End it with `{}`:
```tern {.live}
## 核 {#kernel}
これは@kernel{}です。
```
### Ids are unique {#unique-ids}
Every id names one element. When two elements claim the same id, the first keeps it, the second loses it, and both places are reported. An id you wrote always beats one Tern made up for a heading.
```tern {.live expect="id.duplicate id.duplicate"}
## Kernel
{#kernel}
A paragraph that claims the heading's id: it wins, and the heading becomes `kernel-2`.
{#kernel}
A second claim: this one loses.
```
Four ids belong to Tern itself, for elements it adds to the page: `tern-style`, `tern-color-scheme`, `tern-source` and `tern-diagnostics`. A heading whose made-up id would be one of them gets `-2`; an id you write is dropped, with `id.duplicate`.
```tern {.live expect="id.duplicate"}
## Tern style
{#tern-source}
This paragraph cannot have that id.
```
**Reference:** [references](syntax-inline.html#reference), [reference text](elements.html#references), [numbering](elements.html#numbering), [ids](elements.html#ids), [labels](elements.html#labels).
## Footnotes {#footnotes}
Put `[^label]` where the footnote is referenced, and `[^label]: text` anywhere in the note. Footnotes are numbered in the order they are first referenced and collected at the end, with links back.
```tern {.live}
Subspaces are closed under addition.[^closed] So are kernels.[^kernel]
[^closed]: If $u$ and $v$ are in it, so is $u + v$.
[^kernel]: Every kernel is a subspace.
```
- **Longer footnotes.** Indent continuation lines by two spaces; a blank line followed by an indented line continues the footnote too, so it can hold several paragraphs, lists or code.
- **Labels** can be words or numbers, and their case does not matter: `[^A]` reaches `[^a]:`.
- **Referenced twice**, a footnote keeps its number, and its back link goes to the first reference.
- **Literally:** `\[^1]`, in text or at the start of a line.
```tern {.live}
A claim.[^src] The same source again.[^SRC]
[^src]: The first paragraph of the footnote.
A second paragraph, indented by two spaces.
```
A reference with no definition stays text, with a warning. A definition nobody references is still shown, after the others, with a hint.
```tern {.live expect="footnote.undefined footnote.unused"}
A missing footnote.[^nope]
[^spare]: Nobody points here.
```
**Reference:** [footnote references](syntax-inline.html#footnote-reference), [footnote definitions](syntax-blocks.html#footnote-definition).
## Metadata {#metadata}
A `:::meta` block holds `key: value` lines. Tern writes them into the page's head: the title, the language, and ` ` tags for search engines and link previews. Put it first in the note.
```tern {.live}
:::meta
title: Linear maps: kernel, image and rank
lang: en
author: O. Carrera
date: 2026-10-07
description: Lecture 7 of the linear algebra course.
:::
# Linear maps
```
The block shows nothing in the body. What each key does:
| Key | Becomes |
|---|---|
| `title` | the page's `` |
| `lang`, `dir` | `` and ``; `lang` also picks the language of labels |
| `author`, `date`, `description`, `keywords` | ` ` |
| any other key | ` ` too |
- **No title?** Then the page title is the text of the first `#` heading.
- **Head or `:::meta`.** You can also set these in the head, before the `tern.js` line: ``, ``. When both set a key to different values, the head wins, with a warning. Set each key in one place.
- **Values are plain text.** No markup is parsed in them.
A repeated key keeps its first value; a line that is not `key: value` is reported; and a `:::meta` inside another block is ignored:
```tern {.live expect="meta.duplicate meta.malformed"}
:::meta
title: First
title: Second
just some words
:::
```
There is no front matter. A note that starts with `---` and `key: value` lines renders them as a rule, a paragraph and a rule, and Tern points to `:::meta`:
```tern {.live expect="doc.frontmatter"}
---
title: Old habits
---
```
**Reference:** [metadata](elements.html#metadata), [`meta.conflict`](diagnostics.html#meta-conflict).
## Raw HTML {#raw-html}
Tern covers most of what a document needs, but the full power of HTML is always there. Raw HTML enters a note through three doors, each kept separate from the Tern around it.
### HTML blocks {#html-blocks}
A line that starts with a block-level or custom tag, such as `