Skip to content

Repository files navigation

starlight-codeblocks

A Starlight and Astro plugin that adds 26 features to code blocks, such as focus, line states, annotations, links to API docs and runnable examples. It builds on Expressive Code, so the code blocks you already have keep working.

Using an agent? Point it at the bundled skill.

Install

Add the package to the site:

npm install starlight-codeblocks

Then add codeblocks() to the Starlight plugins in astro.config.mjs:

import starlight from '@astrojs/starlight';
import { defineConfig } from 'astro/config';
import codeblocks from 'starlight-codeblocks';

export default defineConfig({
  integrations: [
    starlight({
      title: 'My docs',
      plugins: [codeblocks()],
    }),
  ],
});

On an Astro site without Starlight, add codeblocks() from starlight-codeblocks/astro to integrations instead. The Astro setup page gives the details.

Most features start only when a code block uses their attribute, or a comment notation directive such as # [!code focus]. A few, such as file icons and colour swatches, apply to every matching block.

The documentation has a page for each feature, with live examples, and a reference for every option.

Features

Each section below shows the smallest syntax for a feature and how it looks to readers. Open a section to see it.

Explain code

Annotations

Add numbered markers to lines. Each marker opens a note in a popover, so the code stays clean until a reader asks.

runs-on: ubuntu-latest # [!annotate] Uses the Ubuntu GitHub Actions runner.
A YAML block with two numbered markers. The mouse cursor clicks each marker. The first note opens out of its marker, beside the line, and the second opens under its marker.

Annotations documentation

Side annotations

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

```py annotations="side"
```
A Python block with its notes in a column beside the code, each note next to its line.

Side annotations documentation

Footnotes

Add numbered badges to lines, with the notes in a list under the block, where readers see them all at once.

# [!ref] Creates the application object.
app = Flask(__name__)
A Python block with numbered badges on two lines and the notes in a list under the block. Clicking a badge highlights its line and its note.

Footnotes documentation

Inline callouts

Put a short note in a bubble above a line, with an arrow that points at the word it explains.

// [!callout /signal/] Lets `controller.abort()` cancel the request.
const res = await fetch(url, { signal: controller.signal });
A JavaScript block with a note in a bubble above a line, with an arrow that points at the word signal.

Inline callouts documentation

Scrollycoding

Explain a code block in prose steps that scroll past it, while the block stays in view and focuses the lines of each step.

import { Scrollycoding, Step } from 'starlight-codeblocks/components';

<Scrollycoding>

```js
```

<Step focus="1">Import Express.</Step>
<Step focus="3">Create the app object.</Step>

</Scrollycoding>
Prose steps scroll past a code block that stays in view. The block focuses the lines of each step.

Scrollycoding documentation

Code walkthrough

Step through versions of one code block, and watch the code move from each version to the next, so readers see what changed.

import { CodeWalkthrough } from 'starlight-codeblocks/components';

<CodeWalkthrough>

```js step="Create the app"
```

```js step="Parse JSON bodies"
```

</CodeWalkthrough>
A JavaScript block with step buttons. Clicking Next moves the code to the next version, and the new lines fade in.

Code walkthrough documentation

Draw attention

Focus

Blur the lines outside a range, so that readers look at the lines that you name first. Every line becomes sharp when a reader hovers over the block or moves keyboard focus into it.

```js focus={4-7}
```
A code block with four sharp lines and the other lines blurred. The mouse cursor moves over the block and every line becomes sharp.

Focus documentation

Line states

Tint lines as errors, warnings, notes or successes, with an optional message after the code, like the diagnostics in a code editor.

for name in sys.argv[1:]  # [!code error] SyntaxError: expected ':'
A Python block with a red error line and a yellow warning line, each with its message after the code, and a blue info line.

Line states documentation

Code mentions

Link a phrase in the prose to lines of the code block below it, so that readers see which lines the text is about.

The [base case](#mention:base) stops the recursion.

```py
    if n == 0:  # [!mention base]
```
A paragraph with two linked phrases above a Python block. The mouse cursor moves over each phrase and the lines it names stay sharp while the others fade.

Code mentions documentation

Make code easier to read

Hidden lines

Hide the imports and set-up that readers need to run an example but not to understand it. The copy button still copies every line.

```py hidden={1-3,6-7}
```
A Python block with dashed lines in place of hidden lines. Clicking a dashed line shows the hidden imports.

Hidden lines documentation

Expandable blocks

Show the first lines of a long block, with a fade and a button to reveal the rest.

```py expandable={8}
```
A Python block that shows its first lines with a fade and a button. Clicking the button shows every line.

Expandable blocks documentation

Visible whitespace

Show spaces and tabs as faint glyphs, for the blocks where indentation changes the meaning of the code.

```make whitespace
```
A Makefile block with a faint arrow for each tab and a faint dot for each leading space.

Visible whitespace documentation

Colourised brackets

Colour matching brackets by nesting depth, so readers can match the pairs on a dense line of code.

```js brackets
```
Four lines of JavaScript. The nested brackets of the call that starts on the second line have a different colour for each depth.

Colourised brackets documentation

Colour swatches

Show a small swatch of each CSS colour next to its value. Readers can click a colour to copy it. Swatches start on their own.

```css
.button { background: rebeccapurple; }
```
A CSS block. A small square in each colour comes before the values #ffffff, rebeccapurple and a semi-transparent rgb() colour.

Colour swatches documentation

File icons

Show the icon of the file type before the title of a code block. The icons come from vscode-icons by default, another coloured icon set, or the Starlight file tree. File icons start on their own.

```json title="package.json"
{ "name": "my-site" }
```
Four code blocks, each with a file icon from a different icon set before its title: src/index.js, app.py, package.json and Dockerfile.

File icons documentation

Inline code highlighting

Give inline code in the prose the syntax colours of the code blocks, from a language suffix or a default language for the site.

> - In JavaScript, `[] + {}{:js}` is `"[object Object]"{:js}`.
A quoted list of four facts, with inline code in JavaScript, Python, CSS and shell syntax colours.

Inline code highlighting documentation

Word-level diff

Highlight the words that changed inside each line of a diff, so readers find a small edit in a long line. It applies to each removed line that an added line follows.

-const timeout = 5000;
+const timeout = options.timeout ?? 5000;
A diff block where only the changed words in each line are tinted, underlined when added and struck through when removed.

Word-level diff documentation

Link code

Code links

Turn text in code into a link with a card that describes it, from a directive in the comment above.

# [!link /linspace/ https://numpy.org/doc/stable/reference/generated/numpy.linspace.html] Returns evenly spaced numbers over an interval.
x = np.linspace(0, 1, 50)
A Python block where the word linspace is a link with a solid underline in the accent colour. The mouse cursor moves over it and a card shows the description and numpy.org.

Code links documentation

API auto-linking

Link the names in code examples to their reference pages, with a card that shows the signature and a summary. Adapters for Python and Nextflow come with the plugin.

import json
from pathlib import Path

run = json.loads(Path("run.json").read_text())
A Python block where library names have dotted underlines. The mouse cursor moves over one and a card shows its signature and a summary.

API auto-linking documentation

Line permalinks

Give a code block line numbers that link to each line, so readers can share a link to the exact lines they mean. Shift-click to select multiple lines.

```yaml id="cfg"
```
A YAML block with line numbers. Clicking a number highlights the line, and a Shift-click extends it to a range.

Line permalinks documentation

Adapt to the reader

Code tabs

Show several code blocks as one, with editor tabs in the title bar. Use it for the files of a project, or the commands for each package manager.

:::code-tabs
```yaml title=".github/workflows/ci.yml"
name: CI
on: push
```
```py title="greet.py"
print("Hello, world!")
```
```js title="greet.js"
console.log('Hello, world!');
```
:::
A code block with three file tabs in the title bar: a GitHub Actions workflow, a Python file and a JavaScript file. Selecting a tab shows that file.

Code tabs documentation

Fill-in placeholders

Turn placeholders such as YOUR_TOKEN into fields, so readers type their own values into every block and the copied code.

```sh placeholder="YOUR_TOKEN"
```
A shell block and a Python block with a YOUR_TOKEN field. Text typed in one field appears in both blocks.

Fill-in placeholders documentation

Copy and run

Smart shell copy

Add a Copy commands button to terminal blocks, which copies the commands without the prompts or the output. It applies to every terminal block with a prompt line, and to Python sessions with >>> prompts.

$ uv tool install ruff
Resolved 1 package in 180ms
A terminal block with prompts and their output. The mouse cursor clicks the Copy commands button in the title bar. A caption below the block then shows the copied text: the commands only, without the prompts or the output.

Smart shell copy documentation

Open in playground

Add a title bar button that opens the example in an online playground, with the code already filled in.

```ts playground="typescript"
```
A TypeScript block with an Open in TS Playground button in its title bar.

Open in playground documentation

Run code

Add a Run code button that runs the example in the browser and shows the output under the block. Python, JavaScript and TypeScript work with no set-up. Python runs with Pyodide, which loads only when a reader clicks Run code, and installs the packages that the code imports.

```py runnable
```
A Python block with a Run code button. Clicking it shows the output of the program under the block.

Run code documentation

Licence

MIT

Releases

Contributors

Languages