Line permalinks
A normal code block has no address for its lines. A reader who asks a question about one setting can only link to the page, or to the heading above the block. Line permalinks give a block line numbers, and each number is a link to its line.
Readers see
You write
```yaml title="config.yml" id="cfg"server: host: 0.0.0.0 port: 8080cache: dir: .cache max_age: 3600logging: level: info```Click a line number to highlight that line. The address of the page changes to #cfg-L2, and the page does not move. Hold Shift and click a second number to highlight every line between the two, as #cfg-L2-L4. Open that address in a new tab, and the page scrolls to the lines and highlights them.
Syntax
Section titled “Syntax”| Syntax | Where |
|---|---|
id="<id>" |
Code block fence line |
The id turns on line numbers for that block. It is also the id of the block in the page, so #cfg links to the whole block. Each block on a page needs its own id.
Pick an id from what the block contains, such as its file name. The id keeps links to the block working when you add other blocks to the page.
Examples
Section titled “Examples”Numbers that match the file
Section titled “Numbers that match the file”A block that shows part of a file can start at the line number of that part, so the numbers match the file:
```py title="app.py" id="app" startLineNumber=41@app.get("/health")def health(): return {"status": "ok"}```With hidden lines and a callout
Section titled “With hidden lines and a callout”This example combines line permalinks with hidden lines and an inline callout on purpose. The hidden-lines marker and the callout arrow line up with the code after the line numbers:
```ts title="server.ts" id="server" hidden={1-2}import { createServer } from 'node:http';import { handler } from './handler.ts';
const port = Number(process.env.PORT ?? 3000);// [!callout /listen/] Starts the server on the port.createServer(handler).listen(port);```Behaviour
Section titled “Behaviour”- The links:
- Each line number links to
#<id>-L<n>, where<n>is the number that the reader sees. If the fence line (the first line of the code block, with the language) hasstartLineNumber, the numbers start there. - Clicking a number highlights that line and changes the address with
history.replaceState. The page does not scroll, and the browser history gets no new entry. - Clicking a number with Shift held highlights the range from the last number you clicked, as
#<id>-L<a>-L<b>.
- Each line number links to
- Opening a link:
- When the page loads, or the address changes, the plugin highlights the lines in the address and scrolls them into view. If a line is a hidden line, its marker opens. If a line is in a
<Tabs>panel that is not selected, its tab opens.
- When the page loads, or the address changes, the plugin highlights the lines in the address and scrolls them into view. If a line is a hidden line, its marker opens. If a line is in a
- Keyboard and screen readers:
- The line numbers are links, so you can reach them with the Tab key and press Enter to highlight a line. Shift and Enter together highlights a range. Screen readers announce each one as “Link to line N”, and the highlighted numbers have
aria-current.
- The line numbers are links, so you can reach them with the Tab key and press Enter to highlight a line. Shift and Enter together highlights a range. Screen readers announce each one as “Link to line N”, and the highlighted numbers have
- Copy:
- Line numbers are not part of the copied text, and a manual selection of the code leaves them out.
- Warnings:
- Two blocks with the same
idon one page cause a build warning.
- Two blocks with the same
- Without JavaScript:
- The links go to their line, without the highlight.
Options
Section titled “Options”Line permalinks have no options. Turn the feature off for the whole site with permalinks: false:
codeblocks({ permalinks: false,});With permalinks: false, the plugin ignores id on the fence line.
Limitations
Section titled “Limitations”- Line numbers take space on the left of every line. On a phone, a block with long lines scrolls sooner.
- The plugin highlights one range at a time on a page. A new highlight in any block removes the old highlight.
- An
idmust not match theidof a heading on the page. Heading ids come from the heading text, such as#options. - The
starlight-links-validatorplugin reports links to a block or a line, such as#cfg-L2, as broken. Give itexclude: linksValidatorExclude, imported fromstarlight-codeblocks.
Related
Section titled “Related”- Line states: mark a line as an error, a warning or a note in the source, for every reader.
- Code mentions: highlight lines from a phrase in the prose, without a line number.
- Hidden lines: keep set-up lines out of view. Their line numbers still count.