Skip to content

Plugin Hooks

Available plugin hooks

The engine calls the following hook functions in the order listed here:

preprocessLanguage

Allows preprocessing the code block’s language identifier before loading language-specific defaults into props.

The Text Markers plugin uses this hook to override the diff language identifier with the language specified in the lang meta option (if given) to allow using diff syntax to mark inserted and deleted lines while using another language for syntax highlighting.

preprocessMetadata

Allows preprocessing the meta string and the language before any plugins can modify the code.

Plugins are expected to use this hook to remove any of their syntax from the meta string. Removed information can either be stored internally or used to create annotations.

As the code still matches the plaintext in the containing Markdown/MDX document at this point, this hook can be used to apply annotations by line numbers.

preprocessCode

Allows preprocessing the code before any language-specific hooks are run.

Plugins are expected to use this hook to remove any of their syntax that could disturb annotation plugins like syntax highlighters. Removed information can either be stored internally or used to create annotations.

Plugins can also use this hook to insert new code, e.g. to add type information for syntax highlighters, or to provide functionality to include external files into the code block.

performSyntaxAnalysis

Allows analyzing the preprocessed code and collecting language-specific syntax annotations.

This hook is used by the syntax highlighting plugin to run the code through Shiki and to create annotations from the returned syntax tokens.

These annotations are then available to the following hooks and will be used during rendering.

postprocessAnalyzedCode

Allows postprocessing the code plaintext after collecting syntax annotations.

Plugins are expected to use this hook to remove any parts from the code that should not be contained in the output. For example, if a plugin added declarations or type information during the preprocessCode hook to provide information to the syntax highlighter, the declarations could now be removed again.

After this hook has finished processing, the plaintext of all code lines becomes read-only.

annotateCode

Allows annotating the final code plaintext.

As the code is read-only at this point, plugins can use this hook to create annotations on lines or inline ranges matching a specific search term.

postprocessAnnotations

Allows applying final changes to annotations before rendering.

After this hook has finished processing, all annotations become read-only and the engine starts rendering the code blocks line by line.

postprocessRenderedLine

Allows editing the AST of a single line of code after all annotations were rendered.

postprocessRenderedBlock

Allows editing the AST of the entire code block after all annotations were rendered and all lines were postprocessed.

postprocessRenderedBlockGroup

Allows editing the ASTs of all code blocks that were rendered as part of the same group, as well as the AST of the group root element that contains all group blocks.

Groups are defined by the calling code. For example, a rehype plugin using Expressive Code to render code blocks could provide authors with a way to group related code blocks together.

This hook is used by the frames plugin to display multiple code blocks as editor file tabs.

Note: Even if a code block is not part of any group, this hook will still be called. Standalone code blocks are treated like a group containing only a single block.

Referenced types

ExpressiveCodeHook

Type: (context) => void | Promise<void>

Type parameters

ParameterValue
ContextTypeExpressiveCodeHookContext

The base type of all hooks. It is a function that gets called by the engine and receives a context object. The context type defaults to ExpressiveCodeHookContext, but can vary by hook, so see the list of available hooks for the correct type.

Arguments

ParameterType
contextContextType

ExpressiveCodeHookContext

A context object that the engine passes to most hook functions.

It provides access to theme-dependent CSS variables, all resolved style variants based on the configured themes and settings, and the config-dependent wrapper class name.

Properties

addGutterElement
Type: (element) => void

Registers a gutter element for the current code block.

The engine calls the renderLine function of the gutter elements registered by all plugins for every line of the code block. The returned elements are then added as children to the line’s gutter container.

Arguments
ParameterType
elementGutterElement
addStyles
Type: (css) => void

Adds CSS styles to the document that contains the rendered code.

All styles are scoped to Expressive Code by default, so they will not affect the rest of the page. SASS-like nesting is supported. If you want to add global styles, you can use the @at-root rule or target :root, html or body in your selectors.

The engine’s render function returns all added styles in a string array along with the rendered group and block ASTs. The calling code must take care of actually adding these styles to the page. For example, it could insert them into a <style> element before the rendered code block.

Note for integration authors: If you are rendering multiple code block groups on the same HTML page, you should deduplicate the returned styles at the page level. Expressive Code deduplicates styles added to the same group before returning them, but is not aware which styles are already present on the page.

Note for plugin authors: If you are adding the same styles to every block, consider using the baseStyles property of the plugin instead. This allows integrations to optionally extract these styles into a separate CSS file.

Arguments
ParameterType
cssstring
codeBlock
config
Type: ResolvedExpressiveCodeEngineConfig

The Expressive Code engine configuration, with all optional properties resolved to their default values.

cssVar
Type: (styleSetting, fallbackValue?) => string

Returns a CSS variable reference for the given style setting. The CSS variable name is automatically generated based on the setting path.

You can optionally pass a fallback value that will be added to the CSS var() function call (e.g. var(--ec-xyz, fallbackValue)) in case the referenced variable is not defined or unsupported. However, this should rarely be the case as the engine automatically generates CSS variables for all style settings if the plugin’s styleSettings property is set.

Arguments
ParameterType
styleSettingStyleSettingPath
fallbackValue?string
Example
cssVar('frames.fontSize')
// ↓↓↓
'var(--ec-frames-fontSize)'
cssVar('frames.fontSize', '2rem')
// ↓↓↓
'var(--ec-frames-fontSize, 2rem)'
cssVarName
Type: (styleSetting) => string

Returns the CSS variable name for the given style setting. The CSS variable name is automatically generated based on the setting path.

Arguments
ParameterType
styleSettingStyleSettingPath
Example
cssVarName('frames.fontSize')
// ↓↓↓
'--ec-frames-fontSize'
groupContents
Type: readonly { codeBlock: ExpressiveCodeBlock }[]
locale
Type: string
styleVariants
Type: StyleVariant[]

PostprocessRenderedLineContext

A context object that the engine passes to the postprocessRenderedLine hook function.

In addition to the properties made available by ExpressiveCodeHookContext, it provides access to information about the line currently being rendered, and allows modifying the rendered output.

Additional properties

line

A reference to the line that is currently being rendered. It is read-only at this point, but you can access all line properties, including its source code and annotations.

lineIndex
Type: number

The 0-based index of the line inside the code block.

renderData
Type: Object

Allows modifying the line’s rendered output. The lineAst property of this object contains the Hypertext Abstract Syntax Tree (HAST) node representing the rendered line.

You have full control over the lineAst property to modify the rendered output. For example, you could add a class name to the line’s root element, or you could wrap the entire line in a custom element.

There is a wide range of existing utility packages that you can use to manipulate HAST elements. For more information, see the list of utilities in the HAST documentation.

Object properties
lineAst
Type: Element
renderEmptyLine
Type: RenderEmptyLineFn

Allows rendering an empty line that is not part of the original code.

Some plugins may need to render lines that are not part of the original code, e.g. to display the expected output of a call right inside the code block. To align such lines with the original code, plugins can request an empty line from the engine using this function.

PostprocessRenderedBlockContext

A context object that the engine passes to the postprocessRenderedBlock hook function.

In addition to the properties made available by ExpressiveCodeHookContext, it provides access to render data of the code block currently being rendered, and allows modifying the rendered output.

Additional properties

renderData
Type: Object

Allows modifying the block’s rendered output. The blockAst property of this object contains the Hypertext Abstract Syntax Tree (HAST) node representing the rendered block.

You have full control over the blockAst property to modify the rendered output. For example, you could add a class name to the block’s root element, wrap the entire block in a custom element, or traverse its children to find specific elements and modify them.

There is a wide range of existing utility packages that you can use to manipulate HAST elements. For more information, see the list of utilities in the HAST documentation.

Object properties
blockAst
Type: Element
renderEmptyLine
Type: RenderEmptyLineFn

Allows rendering an empty line that is not part of the original code.

Some plugins may need to render lines that are not part of the original code, e.g. to display the expected output of a call right inside the code block. To align such lines with the original code, plugins can request an empty line from the engine using this function.

PostprocessRenderedBlockGroupContext

A context object that the engine passes to the postprocessRenderedBlockGroup hook function.

It provides access to information about the code block group currently being rendered, and allows modifying the rendered output.

Properties

addStyles
Type: (css) => void

See ExpressiveCodeHookContext.addStyles.

Arguments
ParameterType
cssstring
pluginStyles
Type: { pluginName: string; styles: string }[]

A list of styles that plugins added to the current code block group using the addStyles hook context function. Each item contains the plugin name and the styles it added. You have full control over the styles at this point and can add, modify or remove them as needed.

renderData
Type: Object

Allows modifying the rendered output of a group of code blocks. The groupAst property of this object contains the Hypertext Abstract Syntax Tree (HAST) parent node surrounding all rendered blocks.

This is the only property that allows you to modify the wrapper element of the entire group. You have full control over it to modify the rendered output. For example, you could add a class name to the group’s root element, or you could wrap the entire group in a custom element.

Object properties
groupAst
Type: Element
renderedGroupContents
Type: readonly { codeBlock: ExpressiveCodeBlock; renderedBlockAst: Element }[]

An array of objects, each containing a reference to the code block, and its rendered HAST output. This is the same HAST element per block that is also available in the renderData property of the postprocessRenderedBlock hook context.