Inline callouts
A code block shows the code, and the prose around it explains it. When the explanation is about one name on one line, a reader must find that name themselves. An inline callout puts the note in a bubble directly above the line, with an arrow that points down at the name.
Readers see
const controller = new AbortController();Lets controller.abort() cancel the request.const res = await fetch(url, { signal: controller.signal });const data = await res.json();You write
```jsconst controller = new AbortController();// [!callout /signal/] Lets `controller.abort()` cancel the request.const res = await fetch(url, { signal: controller.signal });const data = await res.json();```The comment line with [!callout /signal/] is gone from the output. The bubble takes its place, and its arrow points at the middle of the first signal on the line below.
Syntax
Section titled “Syntax”| Syntax | Where |
|---|---|
[!callout /text/] note |
Comment on or above the line |
[!callout] note |
Comment on or above the line |
The directive goes at the end of the line it explains, or on its own line directly above it. /text/ is literal text, not a regular expression. The arrow points at the first match on that line. Without /text/, the arrow points at the first character that is not a space. The note can hold inline code, links and bold text.
Examples
Section titled “Examples”A callout for the whole line
Section titled “A callout for the whole line”A callout without /text/ points at the start of the line. This suits a note about the whole statement:
import sqlite3
Creates the file if it does not exist yet.db = sqlite3.connect("notes.db")db.execute("CREATE TABLE IF NOT EXISTS notes (body TEXT)")```pyimport sqlite3
# [!callout] Creates the file if it does not exist yet.db = sqlite3.connect("notes.db")db.execute("CREATE TABLE IF NOT EXISTS notes (body TEXT)")```Two callouts on one line
Section titled “Two callouts on one line”Two callouts above one line explain two parts of it. The bubbles stack in source order:
How many times to try again after the first attempt.The wait before each retry, in milliseconds.const client = createClient({ retries: 3, backoffMs: 250 });```ts// [!callout /retries/] How many times to try again after the first attempt.// [!callout /backoffMs/] The wait before each retry, in milliseconds.const client = createClient({ retries: 3, backoffMs: 250 });```Behaviour
Section titled “Behaviour”- Where the bubble shows:
- The plugin removes the directive, and its line if the line holds nothing else. The bubble is above the target line.
- The bubble starts 40 px to the left of the arrow, but never closer than 8 px to the edge of the block.
- The bubble is at most 60 characters wide, or 90% of the block. Longer notes wrap inside the bubble, so the block does not get wider.
- On a narrow screen, the target text can be past the right edge of the block. The bubble and its arrow then stay at the right edge, where the reader can see them.
- Two callout lines above one line give two bubbles, in the order you wrote them.
- Highlights:
- If the lines above and below the callout have the same highlight, the callout has it too, so the highlight does not break. This works for marked, inserted and deleted lines and for line states.
- Screen readers:
- Screen readers read the bubble before its line. The bubble has the
noterole.
- Screen readers read the bubble before its line. The bubble has the
- Copy:
- The copy button leaves callouts out. A manual selection of the code leaves them out too.
- To select the text of a bubble, start the selection in the bubble.
- Without JavaScript:
- Callouts are plain HTML and CSS. They work without JavaScript, and they have no animation. Without JavaScript, the text of a bubble cannot be selected.
Options
Section titled “Options”Inline callouts have no options. Turn the feature off for the whole site with callouts: false:
codeblocks({ callouts: false,});With callouts: false, the plugin does not know the [!callout] directive. It leaves the directive line in the code as written, and logs a build warning.
Limitations
Section titled “Limitations”- The plugin counts columns in characters. A tab counts to the next multiple of 2 columns, which is the
tab-sizethe plugin sets on code blocks. If your site sets anothertab-size, arrows on lines with tabs after other characters point at the wrong place. - With Expressive Code’s
wrapattribute, a long line can wrap below its callout. The arrow then points at the first row of the line. - A callout explains one line. For a note about several lines, use annotations or footnotes.
Related
Section titled “Related”- Annotations: numbered markers that open a note only when the reader asks for it.
- Footnotes: numbered notes listed under the block, all visible at once.