Skip to content

Expressive Code plugins

codeblocks() adds every feature to Starlight for you. Behind it, each feature is an Expressive Code plugin. The starlight-codeblocks/expressive-code subpath exports these plugins, and a preset that returns all of them. A site that uses Expressive Code without Starlight, or with its own plugins list in ec.config.mjs, uses them there.

pluginCodeblocks(options) returns every plugin, in the correct order, with the options of codeblocks(). Use the preset unless you have a reason to add plugins one by one. To leave a feature out, set its option to false:

ec.config.mjs
import { pluginCodeblocks } from 'starlight-codeblocks/expressive-code';
export default {
plugins: [pluginCodeblocks({ annotations: false, runnable: false })],
};

On a Starlight site with codeblocks(), call pluginCodeblocks() with no argument. It then reads the options that you gave to codeblocks().

On a site without codeblocks(), give the preset Astro’s base as the second argument, if the site has one. Links in code that start with / then get it in front:

ec.config.mjs
plugins: [pluginCodeblocks({}, { base: '/docs' })],

Each plugin takes the settings of its option, as the options reference lists them. The table gives the plugins in the order that the preset adds them.

Plugin Option Feature
pluginCore() none Shared style settings and styles
pluginNotation(settings) notation Comment notation
pluginFocus(settings) focus Focus
pluginLineStates(settings) lineStates Line states
pluginWordDiff(settings) wordDiff Word-level diff
pluginWhitespace() whitespace Visible whitespace
pluginBrackets(settings) brackets Colourised brackets
pluginSwatches(settings) swatches Colour swatches
pluginShellCopy(settings) shellCopy Smart shell copy
pluginCodeLinks({ base }) codeLinks Code links
pluginApiLinks({ adapters, base }) apiLinks API auto-linking
pluginPlaceholders(settings) placeholders Fill-in placeholders
pluginMentions() mentions Code mentions
pluginPermalinks() permalinks Line permalinks
pluginHiddenLines() hiddenLines Hidden lines
pluginExpandable(settings) expandable Expandable blocks
pluginPlayground(playgrounds) playgrounds Open in playground
pluginRunnable(settings) runnable Run code
pluginFileIcons(settings) fileIcons File icons
pluginCodeTabs(fileIcons) codeTabs Code tabs
pluginWalkthrough() walkthrough Code walkthrough
pluginCallouts() callouts Inline callouts
pluginAnnotations() annotations Annotations and side annotations
pluginFootnotes(settings) footnotes Footnotes

pluginCodeLinks() and pluginApiLinks() take the base of the Astro site, for links that start with /. With codeblocks(), they read it from Astro. pluginApiLinks() has no default adapters. Give it the adapters from starlight-codeblocks/adapters/python and starlight-codeblocks/adapters/nextflow, or your own.

If you add plugins one by one, follow these rules:

  1. Add pluginCore() first. Every other plugin uses its style settings.
  2. Add pluginNotation() second, if any plugin after it reads directives.
  3. Add the other plugins in the order of the table.

The order matters. For example, pluginPlayground() sends the copied text, so it must come after pluginShellCopy() and pluginPlaceholders(), which change that text. pluginCallouts() must come after pluginHiddenLines(), which rebuilds the lines of the block.

Some features need more than an Expressive Code plugin. Without codeblocks(), these parts are not there:

  • The :::code-tabs directive and inline code highlighting need the Markdown plugin that codeblocks() adds.
  • The <CodeWalkthrough> and <Scrollycoding> components need Starlight.
  • runnable.runtimes values are URLs that the browser imports as they are, because codeblocks() is not there to bundle the runtime modules. There are no built-in runtimes. Map each language to the URL of its runtime module, such as https://cdn.jsdelivr.net/npm/starlight-codeblocks/dist/runtimes/pyodide.mjs. The JavaScript and TypeScript runtimes are javascript.mjs and typescript.mjs in the same folder.
  • Expressive Code turns each tab into spaces, because codeblocks() is not there to set tabWidth: 0. Set tabWidth: 0 in ec.config.mjs, so that tabs reach the code blocks unchanged.

The client scripts of interactive features load inline on each page that needs them, so the features work without a change to the build.