---
title: "Side annotations"
description: "Show the notes of an annotated block in a column beside the code, so readers see every note next to its line."
url: "https://ewels.github.io/starlight-codeblocks/features/side-annotations/"
markdown: "https://ewels.github.io/starlight-codeblocks/features/side-annotations.md"
section: "Explain code"
site: "starlight-codeblocks documentation"
context: "This page is from the documentation of starlight-codeblocks. A Starlight plugin that adds focus, line states, annotations, API auto-linking and 22 more features to the code blocks of a site."
index: "https://ewels.github.io/starlight-codeblocks/llms.txt"
---

# Side annotations

> Show the notes of an annotated block in a column beside the code, so readers see every note next to its line.

[Annotations](https://ewels.github.io/starlight-codeblocks/features/annotations/) hide each note in a popover until a reader opens it. For a walkthrough, where readers need every note, that is one click too many. Side annotations use the same `[!annotate]` directive, but show the notes in a column beside the code.

:::tip[Good for:]
A long block with a short note on many of its lines. Readers see every note at once, each beside its line, and the notes work in Markdown and MDX. To explain the code in paragraphs, one step at a time, use [scrollycoding](https://ewels.github.io/starlight-codeblocks/features/scrollycoding/).
:::

````md
```py title="report.py" annotations="side"
import csv
import sys
from collections import Counter
from pathlib import Path


def read_rows(path):
    with path.open() as fh:  # [!annotate] Opens the file and closes it when the block ends.
        return list(csv.DictReader(fh))  # [!annotate] Each row becomes a dict keyed by the header line.


def summarise(rows, key):  # [!annotate] Counts the rows for each value in the column `key`.
    return Counter(r[key] for r in rows)


def main():
    rows = read_rows(Path(sys.argv[1]))
    counts = summarise(rows, "status")
    for status, n in counts.items():
        print(f"{status:<10} {n:>5}")  # [!annotate] Pads the status and count into columns of fixed width.


if __name__ == "__main__":
    main()
```
````

Each annotated line has a small number, and the note with the same number is in the column on the right. Hover over a note, or move keyboard focus to it, to highlight its line. Hover over a line to highlight its note.

## Syntax

| Syntax | Where |
|---|---|
| `annotations="side"` | Code block fence line |
| `[!annotate] note` | Comment at the end of a line |
| `codeSide="right"` | Code block fence line |
| `startNoteNumber={N}` | Code block fence line |
| `annotations.style="filled"`, `annotations.style="outline"` | Code block fence line |

Add `annotations="side"` to the fence line (the first line of the code block, with the language) of a block that uses `[!annotate]`. The directive works as on the [annotations](https://ewels.github.io/starlight-codeblocks/features/annotations/) page. The code is in the left column. To put it in the right column, add `codeSide="right"`. `startNoteNumber={N}` numbers the notes from `N`. `annotations.style` sets the style of the numbers for one block, as for [annotations](https://ewels.github.io/starlight-codeblocks/features/annotations/#options).

## Examples

### Code on the right

`codeSide="right"` puts the code in the right column and the notes in the left column:

````md
```yaml title="config.yml" annotations="side" codeSide="right"
server:
  port: 8080 # [!annotate] The port that the server listens on.
  host: 0.0.0.0 # [!annotate] Listens on every network interface.
log:
  level: info # [!annotate] One of `debug`, `info`, `warn` or `error`.
```
````

### The outline style

`annotations.style="outline"` draws the numbers on the lines as outlined circles in the magenta of the theme:

````md
```py title="greet.py" annotations="side" annotations.style="outline"
import sys # [!annotate] Gives access to the command-line arguments.

name = sys.argv[1] # [!annotate] The first argument after the file name.
print(f"Hello, {name}!") # [!annotate] An f-string puts the value of `name` in the text.
```
````

## Behaviour

- Layout:
  - The code and the notes are two columns when the block's container has space for the longest line beside the notes. The plugin measures the lines at build time and gives each block one of three widths: 600, 800 or 1000 px. In a container narrower than that width, such as on a phone, the notes are a numbered list under the block.
  - At 600 px, the code column shows about 42 characters on a line. At 800 px it shows about 66, and at 1000 px about 90. A line with a number needs 3 characters more, and the first line needs 4 more for the copy button.
  - The notes column is at least 12rem wide.
- Scrolling:
  - The notes column starts level with the top of the block. It sticks below the site header while the block scrolls past.
  - If the notes column is taller than the space below the header, it scrolls with the page instead.
- Highlighting:
  - Hovering over a note, or focusing it with the Tab key, highlights its line. Hovering over a line highlights its note.
  - A number on a line changes colour when the mouse cursor is on it, the same as an annotation marker.
  - Clicking a note or its number keeps the highlight, as for [footnotes](https://ewels.github.io/starlight-codeblocks/features/footnotes/). A second click clears it. Several can stay highlighted. A click anywhere else clears them all.
  - With keyboard focus on a note, Enter or Space keeps or clears its highlight.
- Screen readers:
  - The numbers on the lines are hidden from screen readers. Screen readers read the notes as a list after the code.
- Copy:
  - The copy button leaves the numbers and the notes out.
- Without JavaScript:
  - The layout works, but notes and lines do not highlight each other.
- Motion:
  - Under reduced motion, the highlight changes at once.

## Options

Side annotations have no options of their own. They use the `style` option of [annotations](https://ewels.github.io/starlight-codeblocks/features/annotations/#options), and a block can set its own with `annotations.style="outline"`. `annotations: false` turns them off together with annotations:

```js title="astro.config.mjs"
codeblocks({
  annotations: false,
});
```

- [Configuration](https://ewels.github.io/starlight-codeblocks/configuration/): Learn how to set options for the whole site, or for a single code block.

## Make space for long lines

Starlight's content column is 45rem (720 px) wide on each page that has a sidebar. So on a default page, a block with lines of more than about 42 characters shows the notes as a list under the code.

On a page without a table of contents, the column has free space on each side. A block that needs 800 or 1000 px spreads over that space, so it gets the columns in a wide window. The text stays in the content column.

[See the demo on a page without a table of contents](https://ewels.github.io/starlight-codeblocks/features/side-annotations/wide/)

To use this, turn off the table of contents of the page:

```md title="src/content/docs/guides/walkthrough.md"
---
title: Walkthrough
tableOfContents: false
---
```

- The block spreads only when it is directly on the page. A block in tabs, an aside, a list or a component stays in its column.
- The block spreads by the same amount on each side, and not more than it needs for the columns.
- If the window is too narrow for the columns, the block stays in the content column and shows the list.
- A block that fits the content column does not spread.

## Limitations

- The columns need a container of 600 px or more. Blocks with long lines need a wider container, or a page without a table of contents. Smaller windows and phones get the list under the block.
- The widths are estimates for Starlight's default code font. A larger code font can make a line scroll in the code column.
- Lines of more than about 90 characters scroll inside the code column at every width.
- Each note is next to its number, not next to its line. Notes in the column follow each other from the top of the block.

## Related

- [Annotations](https://ewels.github.io/starlight-codeblocks/features/annotations/): the same notes in popovers, for blocks where most readers do not need every note.
- [Footnotes](https://ewels.github.io/starlight-codeblocks/features/footnotes/): the notes in a list under the block at every width, with badges that link the two.
- [Scrollycoding](https://ewels.github.io/starlight-codeblocks/features/scrollycoding/): prose steps that scroll past the block, which focuses the lines of each step.
