Release Notes
This page combines all release notes of the Expressive Code monorepo.
You can find the source changelogs on GitHub in the subfolders of
packages.
0.41.3
- Fixes WCAG 4.1.2 compliance issue by dynamically adding
role="region"to scrollable code blocks. Thank you @ruslanpashkov!
0.41.2
-
Fixes an issue where the deprecated, but still available
themeoption was not being taken into account during SSR bundle trimming. -
Improves the error message when the
<Code>component is being used on a page without having the Astro integration enabled in the project.
0.41.1
- Fixes a regression that caused inline text markers to be rendered with two layered background colors.
0.41.0
-
Adds new
createInlineSvgUrlexport that creates an inline SVG image data URL from the given contents of an SVG file.You can use it to embed SVG images directly into a plugin’s styles or HAST, or pass it to an existing
styleOverridesicon setting. -
Updates Shiki to the latest version (3.2.2).
This adds support for the strikethrough ANSI control code, updates language grammars and adds the bundled themes
gruvbox-dark-hard,gruvbox-dark-medium,gruvbox-dark-soft,gruvbox-light-hard,gruvbox-light-medium, andgruvbox-light-soft. -
Adds new
preventUnitlessValuesproperty toPluginStyleSettings. Thank you @RantingHuman!Plugins can set this property to an array of style setting paths to prevent unitless values for specific style settings. If the user passes a unitless value to one of these settings, the engine will automatically add
pxto the value. This is recommended for settings used in CSS calculations which would otherwise break if a unitless value is passed. -
Adds a new
hangingIndentprop to all code blocks. Thank you @Signum!By setting this prop to a positive number of columns (either in the opening code fence, as a prop on the
<Code>component, or in thedefaultPropsconfig option), you can now further refine the indentation of wrapped lines.If the prop
preserveIndentistrue(which is the default), thehangingIndentvalue is added to the indentation of the original line. IfpreserveIndentisfalse, the value is used as the fixed indentation level of all wrapped lines.This option only affects how the code block is displayed and does not change the actual code. When copied to the clipboard, the code will still contain the original unwrapped lines.
-
Extends ANSI formatting support to allow background colors and strikethrough text. Thank you @dhruvkb!
-
Adds the following new
styleOverridessettings:frames.copyIcon: Allows overriding the SVG icon used for the copy button. Thank you @louisescher!frames.terminalIcon: Allows overriding the SVG icon used for the terminal window frame. Defaults to three dots in the top left corner.
-
Adds support for
bgColorandstrikethroughtoInlineStyleAnnotation. Thank you @dhruvkb! -
Uses the new
preventUnitlessValuesproperty ofPluginStyleSettingsto make style calculations in the plugins “Collapsible Sections”, “Frames” and “Text Markers” more robust. -
Adds the following new
styleOverridessettings:collapsibleSections.expandIconandcollapsibleSections.collapseIcon: Allows overriding the SVG icons used for the expand/collapse buttons.
0.40.2
- Prevents the default style reset from interfering with more complex SVGs inside Expressive Code blocks. Now, not only
pathelements, but all SVGs and their contents are excluded from the reset. Thank you @xt0rted!
0.40.1
- Removes unnecessary end padding from the first code line if the copy to clipboard button is disabled. Thank you @goulvenclech!
0.40.0
-
Adds new
collapseStyleprop to@expressive-code/plugin-collapsible-sections. Thank you @nerdymomocat!The new prop allows selecting one of the following collapsible section styles:
github: The default style, similar to the one used by GitHub. A summary line with an expand icon and the default textX collapsed linesis shown. When expanded, the summary line is replaced by the section’s code lines. It is not possible to re-collapse the section.collapsible-start: When collapsed, the summary line looks like thegithubstyle. However, when expanded, it remains visible above the expanded code lines, making it possible to re-collapse the section.collapsible-end: Same ascollapsible-start, but the summary line remains visible below the expanded code lines.collapsible-auto: Automatically selectscollapsible-startorcollapsible-endbased on the location of the collapsible section in the code block. Usescollapsible-startunless the section ends at the bottom of the code block, in which casecollapsible-endis used.
0.39.0
-
Adds new config option
shiki.engine.Allows selecting the Shiki RegExp engine to be used for syntax highlighting. The following options are available:
'oniguruma': The default engine that supports all grammars, but requires a target environment with WebAssembly (WASM) support.'javascript': A pure JavaScript engine that does not require WASM. The Shiki team is continuously improving this engine and aims for full compatibility with the Oniguruma engine. Use this engine if your target environment does not support WASM.
-
Adds new config option
shiki.bundledLangs.Allows defining a subset of language IDs from the full Shiki bundle that should be available for syntax highlighting.
In server-side rendering (SSR) environments, setting this option to the languages used on your site can reduce bundle size by up to 80%.
If this option is not set, all languages from the full Shiki bundle are available.
-
Adds new config option
removeUnusedThemes.In Astro and Starlight, Expressive Code now automatically removes any themes from the bundle that are not used by your
themesconfiguration. This reduces the SSR bundle size by over 1 MB.This new optimization is enabled by default and does not need to be configured for most sites. If you have an advanced use case that requires access all bundled themes, you can set this option to
false. -
Adds new config option
shiki.langAlias.Allows defining alias names for languages. The keys are the alias names, and the values are the language IDs to which they should resolve.
The values can either be bundled languages, or additional languages defined in
shiki.langs.For example, setting
langAlias: { mjs: 'javascript' }allows usingmjsin your code blocks as an alias for thejavascriptlanguage. -
Updates Shiki to the latest version (1.26.1).
0.38.3
- Makes the types used by the
shiki.langsconfig option less strict to align them better with actual grammars found in the wild. This attempts to reduce the amount of type errors that occurred before when using external grammars, while still being supported by the language processing code.
0.38.2
-
Fixes an issue where the optional
getBlockLocalecallback function was not called when using the<Code>component. Thank you @HiDeoo!As the parent document’s source file path is not available from an Astro component, the
fileproperty passed to thegetBlockLocalecallback function now contains an additionalurlproperty that will be set to the value ofAstro.urlin this case.When determining the locale of a code block, it is recommended to use this new property first, and only fall back to the existing
pathandcwdproperties ifurlis undefined. -
Fixes an issue where the
tabWidthsetting was not applied when using the<Code>component. Thank you @mrchantey!
0.38.1
- Fixes invalid CSS file links when using the
Codecomponent together withplugin-collapsible-sectionsandpnpm. Thank you @simonporter007 and @ayZagen for the report!
0.38.0
-
Updates Shiki to the latest version (1.22.2).
-
Adds config merging functionality to
astro-expressive-code, which allows usingec.config.mjstogether with other configuration sources like the Astro / Starlight config or Starlight themes.Options defined in
ec.config.mjshave the highest priority and will override any corresponding values coming from other configuration sources.For the following object options, a deep merge is performed instead of a simple override:
defaultPropsframesshikistyleOverrides
The following array options are concatenated instead of being replaced:
shiki.langs
-
Adds new config option
shiki.injectLangsIntoNestedCodeBlocks.By default, the additional languages defined in the
shiki.langsoption are only available in top-level code blocks contained directly in their parent Markdown or MDX document.Setting the new
shiki.injectLangsIntoNestedCodeBlocksoption totruealso enables syntax highlighting when a fenced code block using one of your additionallangsis nested inside an outermarkdown,mdormdxcode block. Example:````mdThis top-level Markdown code block contains a nested `my-custom-lang` code block:```my-custom-langThis nested code block will only be highlighted using `my-custom-lang`if `injectLangsIntoNestedCodeBlocks` is enabled.``````` -
Allows overriding bundled languages using the
shiki.langsoption. Thank you @Robot-Inventor!The Shiki language loading logic has been improved to allow passing custom versions of bundled languages without the risk of them being overwritten by the bundled version later.
-
Adds on-demand Shiki language loading to speed up dev server startup and build times while simultaneously decreasing memory usage. Thank you, @fweth!
0.37.1
- Adds
aria-hidden="true"to line numbers to prevent them from being read out loud and interrupting the flow of the code. Thank you @Yesterday17!
0.37.0
- Updates peer dependency range to support Astro 5.
0.36.1
- Fixes type incompatibility with Astro v4.15. Thank you @delucis!
0.36.0
-
Adds the experimental
transformersoption to the Shiki plugin. Thank you @MichaelMakesGames!This option allows you to specify a list of Shiki transformers to be called during syntax highlighting.
Important: This option is marked as experimental because it only supports a very limited subset of Shiki transformer features right now. Most importantly, transformers cannot modify a code block’s text contents in any way, so most popular transformers will not work.
In its current state, this option allows you to use transformers that solely modify the tokens produced by Shiki to improve syntax highlighting, e.g. applying bracket matching or changing the color of certain tokens.
Attempting to pass incompatible transformers to this option will throw an error. This is not a bug, neither in Expressive Code, nor in Shiki or the transformers. Please do not report incompatibilities to other authors, as they are unable to fix them. The current limitations exist because the Shiki transformer API is incompatible with Expressive Code’s architecture, and we will continue to work on closing the gap and improving this feature.
-
Updates Shiki dependency to the latest version.
0.35.6
- Hides the copy code button in case JavaScript is disabled. Thank you @imkunet!
0.35.5
-
Fixes a Vite warning about
emitFile()usage. Thank you @evadecker and @alexanderniebuhr!To avoid this warning from being incorrectly triggered, the Vite plugin internally used by
astro-expressive-codehas now been split into two separate plugins, making sure thatemitFileis only seen by Vite during build.
0.35.4
- Improves performance of client script managing
tabindexon code samples. Thanks @delucis!
0.35.3
- Fixes file names containing
+not being recognized in file name comments. Thank you @amandaguthrie!
0.35.2
- Fixes text marker labels including special characters like
\by properly escaping CSS variable contents. Thank you @stancl!
0.35.1
-
Fixes style and script assets not loading properly when used with MDX in Next.js.
The MDX processing chain used by current Next.js versions caused unwanted escaping of the Expressive Code inline assets, which resulted in hydration issues and prevented features that depend on JS modules like the copy button from working.
In these cases, Expressive Code now uses a different approach to inject the inline assets to ensure that no unwanted escaping occurs.
0.35.0
-
Adds the new package
rehype-expressive-codeas the successor toremark-expressive-code, which is now considered deprecated.If you’re using the Astro integration
astro-expressive-code, you will be automatically using the new package and don’t need to do anything.If your project has a dependency on
remark-expressive-code, you should replace it withrehype-expressive-codeand pass it as a rehype plugin instead of a remark plugin. See the installation instructions for an example.The new package includes performance improvements and also works with the latest versions of MDX in popular site generators.
0.34.2
- Updates dependencies to the latest versions. Thank you @bluwy!
0.34.1
-
Fixes a11y property
tabindex="0"being set on non-scrollable code blocks.Instead of always adding
tabindex="0"to the<pre>element of code blocks, a small JS module is now used to conditionally add the property to scrollable code blocks only. This ensures that scrollable regions can be accessed via keyboard navigation while avoiding audit warnings abouttabindexbeing used on non-scrollable elements.
0.34.0
-
Merges JS modules into a single JS file asset to reduce the number of requests if multiple plugins add JS code.
-
Updates dependencies
hast,hastscriptandhast-util-*to the latest versions.Potentially breaking change: Unfortunately, some of the new
hasttypes are incompatible with their old versions. If you created custom plugins to manipulate HAST nodes, you may need to update your dependencies as well and probably change some types. For example, if you were using theParenttype before, you will probably need to replace it withParentsorElementin the new version. -
Adds a new
/hastentrypoint to@expressive-code/core,expressive-code,remark-expressive-codeandastro-expressive-codeto simplify plugin development.This new entrypoint provides direct access to the correct versions of HAST types and commonly used tree traversal, querying and manipulation functions. Instead of having to add your own dependencies on libraries like
hastscript,hast-util-selectorunist-util-visitto your project and manually keeping them in sync with the versions used by Expressive Code, you can now import the internally used functions and types directly from this new entrypoint. -
Improves plugin development experience by automatically restarting the dev server if any files imported into
ec.config.mjsare changed.Before this update, only changes to
ec.config.mjsitself were detected, so plugin development had to be done inside the config file if you wanted to see your changes reflected live in the dev server. Now, you can also develop your plugins in separate files and get the same experience.Note: As this feature relies on Vite’s module dependency graph, it currently only works if there is at least a single
<Code>component on the page (which uses imports handled by Vite). -
Ensures that static assets (styles and JS modules) are prerendered when using SSR adapters. Thank you @alexanderniebuhr!
To achieve this, the previous approach of using
injectRoutewas dropped and the assets are now being handled by the Vite plugin. -
Makes
astro-expressive-codecompatible with SSR adapters.To achieve this, the code responsible for loading the optional
ec.config.mjsfile was replaced with a new version that no longer requires any Node.js-specific functionality. -
Makes Expressive Code compatible with Bun. Thank you @tylergannon for the fix and @richardguerre for the report!
This fixes the error
msg.match is not a functionthat was thrown when trying to use Expressive Code with Bun.Additionally, the
typemodifier was added to some imports and exports to fix further Bun issues with plugins and integrations found during testing. -
Potentially breaking change: Since this version, all packages are only distributed in modern ESM format, which greatly reduces bundle size.
Most projects should not be affected by this change at all, but in case you still need to import Expressive Code packages into a CommonJS project, you can use the widely supported
await import(...)syntax. -
Adds a
data-languageattribute to the<pre>element of rendered code blocks.The value is set to code block’s syntax highlighting language as specified in the opening code fence or
<Code lang="...">attribute (e.g.jsormd).If a code block has no language specified, it will default to
plaintext.You can use this attribute to apply styles to code blocks based on their language.
-
Adds
definePluginexport to@expressive-code/coreand all integrations to help define an Expressive Code plugin.Using this function is recommended, but not required. It just passes through the given object, but it also provides type information for your editor’s auto-completion and type checking.
-
Allows annotations to be defined as plain objects without the need to extend a class, as long as they have all properties required by
ExpressiveCodeAnnotation. -
Fixes types of
PartialAstroConfigto matchAstroConfigtypes. -
Clones internal TinyColor instance with an object input instead of string input for faster parsing performance. Thanks @bluwy!
0.33.5
-
Updates handling of Astro config option
build.assetsPrefixto support new file extension-based alternatives added in Astro 4.5.0. -
Improves word wrap behavior on very narrow screens and when using larger font sizes by allowing wrapping to start at column 20 instead of 30.
-
Adds
prerender: trueflag to injected asset routes to enable hybrid rendering once it’s also supported for.tsentrypoints by Astro.
0.33.4
- Rolls back even more plugin-shiki changes. They will be re-added later. :)
0.33.3
- Reverts language loading of
plugin-shikito the previous behavior to work around an apparent race condition.
0.33.2
- Improves error logging in case any plugin hooks fail.
0.33.1
- Fixes an issue where lines containing a very long word after the initial indentation would wrap incorrectly.
0.33.0
-
Adds word wrap support to all Expressive Code blocks.
By setting the new
wrapprop totrue(either in the opening code fence, as a prop on the<Code>component, or in thedefaultPropsconfig option), word wrapping will be enabled, causing lines that exceed the available width to wrap to the next line. The default value offalsewill instead cause a horizontal scrollbar to appear in such cases.The word wrap behavior can be further customized using the new
preserveIndentprop. Iftrue(which is the default), wrapped parts of long lines will be aligned with their line’s indentation level, making the wrapped code appear to start at the same column. This increases readability of the wrapped code and can be especially useful for languages where indentation is significant, e.g. Python.If you prefer wrapped parts of long lines to always start at column 1, you can set
preserveIndenttofalse. This can be useful to reproduce terminal output. -
Adds a new gutter API that allows plugins to render gutter elements before code lines.
Using the new
addGutterElementAPI accessible through the hook context argument, plugins can add gutter elements to a code block. The function expects an object matching the newGutterElementinterface.During rendering, the engine calls the
renderLinefunction 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.Potentially breaking change: To properly support all combinations of gutter elements and line wrapping, the rendered HTML tree of code blocks had to be changed. The code contents of each line are now wrapped inside an extra
<div class="code">...</div>element:<div class="ec-line"><div class="code"><span style="...">contents</span>[...more contents...]</div></div>If gutter elements were added to a code block, an optional
<div class="gutter">...</div>will be rendered before this new code wrapper:<div class="ec-line"><div class="gutter">[...gutter elements...]</div><div class="code"><span style="...">contents</span>[...more contents...]</div></div> -
Adds
ExpressiveCodeBlock.propsproperty anddefaultPropsconfig option.The underlying
ExpressiveCodeBlockPropsinterface provides a type-safe way for plugins to extend Expressive Code with their own props using declaration merging. Plugins should use thepreprocessMetadatahook to merge options specified in the opening code fence into their props, makingpropsthe single source of truth for all per-block options.In addition, the new
defaultPropsconfig option allows you to specify default props that will automatically be set on all fenced code blocks and<Code>components by the engine. This saves you from having to specify the same props on every block, while still allowing to override them on an individual basis.The
defaultPropsoption also supports anoverridesByLangproperty, which allows to override the default props for a specific syntax higlighting language. -
Adds
metaOptionsread-only property toExpressiveCodeBlockinstances.This new property contains a parsed version of the code block’s
metastring. This allows plugins to easily access the options specified by users in the opening code fence of a code block, without having to parse themetastring themselves.All official plugins now use this new API to merge any meta options into the new extensible
ExpressiveCodeBlock.propsproperty. -
Migrates syntax highlighting back to Shiki.
After the improvements made in Shikiji were merged back into Shiki, Expressive Code now uses Shiki again for syntax highlighting.
Potentially breaking: Although we performed a lot of testing, the migration might cause slightly different highlighting in some cases, as the latest full bundle of Shiki includes various new and updated grammars. We recommend checking if syntax highlighting still looks as expected on your site.
-
Adds
nuandnushellto the list of terminal languages. Thanks @jacobdalamb! -
Adds new
collapsePreserveIndentprop to@expressive-code/plugin-collapsible-sectionsand replacesstyleOverridespropertyclosedPaddingwithclosedPaddingBlock.The new prop determines if collapsed section titles (
X collapsed lines) should be indented to preserve the minimum indent level of their contained collapsed code lines. This allows collapsed sections to integrate better with the surrounding code. Defaults totrue.Breaking change: If you used the
styleOverridespropertyclosedPaddingbefore to change the default padding around closed collapsed section headings, you must now useclosedPaddingBlockinstead. While the old property supported specifying paddings for all four sides, the new property only supports paddings in the block direction (top and bottom in horizontal writing mode). This change was necessary to make collapsed sections compatible with line wrapping and gutter elements. -
Releases initial version of new optional plugin
@expressive-code/plugin-line-numbers.See the full plugin documentation for more information.
0.32.4
-
Improves automatic color contrast correction when using CSS variables in styleOverrides. Thanks @heycassidy!
It is now possible to use CSS variables in the
styleOverridessettingcodeBackgroundwithout negatively affecting the automatic color contrast correction controlled by theminSyntaxHighlightingColorContrastsetting. If a CSS variable is encountered that cannot be resolved to a color value on the server, Expressive Code now automatically uses the theme’s background color as a fallback for color contrast calculations. You can also provide your own fallback color using the CSS variable fallback syntax, e.g.var(--gray-50, #f9fafb).
0.32.3
- Improves error messages in case an
ec.config.mjsfile was found, but could not be loaded.
0.32.2
- Fixes a race condition with missing styles when multiple
<Code>components are rendered on the same page.
0.32.1
- Fixes virtual API module not resolving without direct package dependency.
0.32.0
-
Adds a
<Code>component that can be used to render code blocks with dynamic contents.In addition to rendering fenced code blocks in markdown & MDX documents, the Expressive Code Astro integration now also provides a
<Code>component that can be used from.astroand.mdxpages.The
<Code>component provides props likecode,langormetathat allow you to dynamically define a code block’s contents. Using this component, you can render code blocks from variables or data coming from external sources like files, databases or APIs.
0.31.0
-
It is now possible to add text labels to marked lines. Thanks @bdenham!
The label text is rendered inside a colorful box in the first line of the marked range. This allows you to reference specific parts of your code in the surrounding text.
To add any text as a label, enclose it in single or double quotes and add it directly after the opening curly brace, followed by a colon (
:). For example,ins={"A":6-10}would mark lines 6 to 10 as inserted and add the labelAto them.
0.30.2
-
Fixes missing CSS output for
uiFontWeightandcodeFontWeightstyle settings. Changed font weights are now properly respected. Thank you @depatchedmode! -
Individual code blocks can now be switched to the base theme while an alternate theme is selected on the page level.
Expressive Code differentiates between your base theme (= the first theme in
themes) and your alternate themes (= any other entries inthemes). Previously, as soon as an alternate theme was selected on the page level, e.g. by using<html data-theme="some-theme-name">, it wasn’t possible to switch individual code blocks to the base theme anymore because of selector specificity issues. This has been resolved and block-level overrides should work as expected now. -
Fixes unexpected
InlineStyleAnnotationbehaviors to improve DX for plugin authors.- Inline styles now use
:where()in selectors to reduce specificity and make them easier to override. - When applying multiple overlapping inline styles to the same line, render phases are now properly respected and later styles override earlier ones.
- The
styleVariantIndexproperty is no longer required. Inline styles without an index now apply to all style variants. - The default
InlineStyleAnnotationrender phase is nownormal. The previous default settingearliestis now explicitly applied byplugin-shikiinstead. This improves the API while still rendering syntax highlighting in theearliestphase to allow other annotations to wrap and modify the highlighted code.
- Inline styles now use
-
Themes that use transparency in unexpected places (e.g. the
rose-pinethemes) are now displayed correctly.
0.30.1
-
Fixes parallel execution of multiple syntax highlighter creations and tasks.
The Shiki plugin now ensures that async tasks like creating syntax highlighters, loading themes or languages are never started multiple times in parallel. This improves performance, reduces memory usage and prevents build errors on large sites.
0.30.0
-
Potentially breaking: Increases minimum supported Astro version to 3.3.0 (when Astro switched to Shikiji).
-
Changes the syntax highlighter used by
plugin-shikito Shikiji. Adds ashiki: { langs: [...] }option for loading custom languages.This change should not cause any differences in HTML output as all rendering is done by Expressive Code. The new
langsoption allows registering custom TextMate grammars in JSON form.
0.29.4
-
Unknown code block languages now log a warning and render as plaintext instead of throwing an error.
-
Adds the config option
useStyleReset.This option determines if code blocks should be protected against influence from site-wide styles. This protection was always enabled before this release and could not be turned off.
When enabled, Expressive Code uses the declaration
all: revertto revert all CSS properties to the values they would have had without any site-wide styles. This ensures the most predictable results out of the box.You can now set this to
falseif you want your site-wide styles to influence the code blocks. -
Sets
prerender = truefor injected routes to improve adapter support.
0.29.3
- Fixes a warning in Astro 4 due to renamed “entryPoint” property. Adds Astro 4 to allowed peer dependencies.
0.29.2
- Comments like
// ...are now no longer incorrectly detected as file names. Thanks @kdheepak!
0.29.1
- Fixes asset URLs when using non-default Astro config options for
base,build.assetsorbuild.assetsPrefix.
0.29.0
-
Updates default fonts to match Tailwind CSS.
The previous set of default fonts could result in very thin character line widths on iOS devices. This is now fixed by using the same widely tested set of fonts that Tailwind CSS uses.
-
Cleans up frontmatter after file name comment extraction.
If a file name comment gets extracted from a code block without a
titleattribute, additional cleanup work is now performed on the surrounding lines:- If the code block’s language supports frontmatter, and the comment was located in a frontmatter block that has now become empty, the empty frontmatter block gets removed.
- If the line following the removed comment (or removed frontmatter block) is empty, it gets removed as well.
0.28.2
- Uses
import typein route handlers to avoid potentialAPIRoutewarning.
0.28.1
-
Adds missing
filesentry to makeemitExternalStylesheetoption work.Sadly, this bug didn’t occur before actually publishing the package - it worked fine when linking the package locally. Sorry about that!
0.28.0
-
Adds
emitExternalStylesheetoption.Determines if the styles required to display code blocks should be emitted into a separate CSS file rather than being inlined into the rendered HTML of the first code block per page. The generated URL
_astro/ec.{hash}.cssincludes a content hash and can be cached indefinitely by browsers.This is recommended for sites containing multiple pages with code blocks, as it will reduce the overall footprint of the site when navigating between pages.
Important: To actually benefit from caching, please ensure that your hosting provider serves the contents of the
_astrodirectory as immutable files with a long cache lifetime, e.g.Cache-Control: public,max-age=31536000,immutable.Defaults to
true.
0.27.1
- Fixes missing
styleOverrides.collapsibleSectionsdeclaration even after importing@expressive-code/plugin-collapsible-sections. Thanks @fflaten!
0.27.0
-
Adds
useDarkModeMediaQueryconfig option.This new option determines if CSS code is generated that uses a
prefers-color-schememedia query to automatically switch between light and dark themes based on the user’s system preferences.Defaults to
trueif yourthemesoption is set to one dark and one light theme (which is the default), andfalseotherwise. -
Rendering multiple themes no longer generates duplicate CSS and HTML output.
In previous versions, a full set of CSS styles was generated for each individual theme, and each code block was rendered multiple times to include the HTML for each theme.
In this version, the CSS output has been changed to a single static set of base styles that uses CSS variables to allow efficient switching between themes.
Also, the HTML output for code blocks is now generated only once, and theme-dependent styles are applied using CSS variables.
These changes significantly reduce page size when using multiple themes, especially on pages with many code blocks.
If you have added CSS code to your site that relies on the old output (e.g. by selectively hiding or showing theme-specific code blocks based on their class name), you will need to update it to work with the new output.
Note: Before writing new custom CSS, please consider if you can achieve your desired result out of the box now. For example, if your
themesoption contains one dark and one light theme, theuseDarkModeMediaQueryoption will generate aprefers-color-schememedia query for you by default. -
Adds
minSyntaxHighlightingColorContrastconfig option.This new option determines if Expressive Code should process the syntax highlighting colors of all themes to ensure an accessible minimum contrast ratio between foreground and background colors.
Defaults to
5.5, which ensures a contrast ratio of at least 5.5:1. You can change the desired contrast ratio by providing another value, or turn the feature off by setting this option to0. -
Config option
textMarkerscan no longer be an object.In previous versions, the
textMarkersconfig option could be an object containing plugin options. This is no longer supported, as the only option that was available (styleOverrides) has been nested into the top-levelstyleOverridesobject now./** @type {import('remark-expressive-code').RemarkExpressiveCodeOptions} */const remarkExpressiveCodeOptions = {textMarkers: {styleOverrides: {markHue: '310',},},styleOverrides: {textMarkers: {markHue: '310',},// You could override other plugin styles here as well:// frames: { ... },},}, -
Moves all plugin styles into nested sub-objects of top-level config option
styleOverrides.In previous versions, there could be multiple
styleOverridesscattered through the configuration (one per plugin with configurable style settings). This has been simplified to a single top-levelstyleOverridesobject that contains all style overrides.Plugins can contribute their own style settings to this object as well by nesting them inside under their plugin name.
/** @type {import('remark-expressive-code').RemarkExpressiveCodeOptions} */const remarkExpressiveCodeOptions = {frames: {showCopyToClipboardButton: false,styleOverrides: {shadowColor: '#124',},},styleOverrides: {frames: {shadowColor: '#124',},// You could override other plugin styles here as well:// textMarkers: { ... },},}, -
Renames config option
themetothemes.Efficient multi-theme support using CSS variables is now a core feature, so the
themeoption was deprecated in favor of the new arraythemes.Please migrate your existing config to use
themesand ensure it is an array. If you only need a single theme, yourthemesarray can contain just this one theme. However, please consider the benefits of providing multiple themes./** @type {import('remark-expressive-code').RemarkExpressiveCodeOptions} */const remarkExpressiveCodeOptions = {theme: 'dracula',// Rename to `themes` and ensure it is an array// (also consider adding a light theme for accessibility)themes: ['dracula'],}, -
Adds
cascadeLayerconfig option.This new option allows to specify a CSS cascade layer name that should be used for all generated CSS styles.
If you are using cascade layers on your site to control the order in which CSS rules are applied, set this option to a non-empty string, and Expressive Code will wrap all of its generated CSS styles in a
@layerrule with the given name. -
Removes engine properties
configClassNameandthemeClassName.The
configClassNameproperty was previously used to add a config-dependent class name to the CSS selectors used to style code blocks.As this property was automatically calculated by hashing the configuration object, it introduced a level of unpredictability, which has now been removed in favor of static base styles.
The
themeClassNameproperty was previously used to add a theme-dependent class name to code blocks. Its format wasec-theme-<name>, where<name>was the kebab-cased name of the theme.As code blocks are now styled using CSS variables instead of generating multiple blocks for all themes and attaching class names to them, this property is no longer needed.
0.26.2
-
Fixes multiple different inline marker types on the same line. Thanks @7c78!
The logic inside
flattenInlineMarkerRangeshad a flaw that caused various combinations ofmark,insanddelinline markers on the same line to fail. This was fixed and more tests were added.
0.26.1
- Re-initialize copy to clipboard buttons after Astro view transitions.
0.26.0
-
Themed selection now keeps the code foreground color intact (like VS Code).
Color overlays no longer prevent text from being selectable.
-
Makes code blocks accessible by keyboard.
-
Improves caching logic to respect theme contents in addition to name.
0.25.0
-
Improves theme loading by allowing to pass more theme types directly.
The
themeconfig option now supports the following value types:- any theme object compatible with VS Code or Shiki (e.g. imported from an NPM theme package)
- any ExpressiveCodeTheme instance (e.g. using
ExpressiveCodeTheme.fromJSONString(...)to load a custom JSON/JSONC theme file yourself) - if you are using a higher-level integration like
remark-expressive-codeorastro-expressive-code:- any theme name bundled with Shiki (e.g.
dracula)
- any theme name bundled with Shiki (e.g.
- any combination of the above in an array
-
Adds more colors to
ExpressiveCodeTheme.applyHueAndChromaAdjustments, allows chaining.The
applyHueAndChromaAdjustments()function now also adjuststitleBar.activeBackgroundandtitleBar.borderproperly. Also, it returns theExpressiveCodeThemeinstance to allow chaining.
0.24.0
-
Renders frame borders on top of background, adds
editorActiveTabHighlightHeightstyle setting.Previously, borders were rendered around the editor / terminal window, which could lead to unwanted empty margins between the window background and the drop shadow (e.g. in theme
nord). Now, the border is rendered on top of the background to resolve this issue, making fully transparent borders act like padding instead.Additionally, the
editorActiveTabHighlightHeightstyle setting was introduced, which allows customizing the colorful line that highlights the active editor tab. It defaults toborderWidth. -
Migrates i18n functions to string templates with plural support.
Translated texts including dynamic parts (e.g. a line count) previously used a function syntax. This was convenient to use during plugin development, but made it impossible to use the popular JSON file format as a source of translated texts. To make it easier to integrate Expressive Code, this release gets rid of the function syntax and adds a
formatTemplatefunction that understands a simple string template syntax including placeholders and plural support.Simple placeholders are written as variable names in curly brackets, e.g.
{variableName}.You can also use conditional placeholders by separating multiple choices with semicolons and optionally adding a condition before each choice, e.g.
{itemCount;1=item;items}or{variableName; 0=zero; >0=positive; negative}. -
Passes global
styleOverridesto plugin style resolver functions.This allows plugins to access their individual
styleOverridesextensions even when values were defined at the global config level.
0.23.0
-
Adds config option
customizeTheme.This optional function is called once per theme during engine initialization with the loaded theme as its only argument.
It allows customizing the loaded theme and can be used for various purposes:
- You can change a theme’s
nameproperty to influence its generated CSS class name (e.g.theme.name = 'dark'will result in code blocks having the classec-theme-dark). - You can create color variations of themes by using
theme.applyHueAndChromaAdjustments().
- You can change a theme’s
-
Adds plugin styles to the
styleOverridesconfig option.So far, this object only contained core styles like colors, fonts, paddings and more. Now, plugins also contribute their own style settings to this object.
For example, if the
framesplugin is installed, you can now override itsshadowColorby settingstyleOverrides.frames.shadowColorto a color value. -
Adds
applyHueAndChromaAdjustmentsfunction toExpressiveCodeTheme.You can now apply chromatic adjustments to entire groups of theme colors while keeping their relative lightness and alpha components intact. This can be used to quickly create theme variants that fit the color scheme of any website or brand.
Adjustments can either be defined as hue and chroma values in the OKLCH color space (range 0–360 for hue, 0–0.4 for chroma), or these values can be extracted from hex color strings (e.g.
#3b82f6).You can target predefined groups of theme colors (e.g.
backgrounds,accents) and/or use thecustomproperty to define your own groups of theme colors to be adjusted. -
Adds outer wrapper when rendering multiple themes.
When the
themeoption is set to an array containing multiple themes, the rendered code block groups are now wrapped inside<div class="ec-themes-wrapper">...</div>. This encapsulates all rendered themes in a single element and thereby ensures their consistent positioning on sites that would otherwise add margins between them due to adjacent sibling combinators. -
Adds
styleOverridestoExpressiveCodeTheme.Themes can now provide their own
styleOverrides, which take precedence over globalstyleOverridesand the default styles. -
Adds support for extracting file names from CSS file comments.
0.22.2
- Hides summary marker on Safari for collapsible section.
0.22.1
- Fixes shifted collapsible sections when other plugins add or remove lines.
0.22.0
- Implements the plugin-collapsible-sections plugin, which adds support for collapsed sections of code. These sections hide a number of code lines until the user chooses to expand them. Thanks @birjj for the contribution!
0.21.0
-
Adds multi-theme support to the
themeconfig option.You can now pass an array of themes to the
themeconfig option ofremark-expressive-codeandastro-expressive-code.This allows you to render each code block in your markdown/MDX documents using multiple themes, e.g. to support light and dark modes on your site.
Note: If you use this feature, you will also need to add custom CSS code to your site to ensure that only one theme is visible at any time.
To allow targeting all code blocks of a given theme through CSS, the theme property
nameis used to generate kebap-cased class names in the formatec-theme-${name}. For example,theme: ['monokai', 'slack-ochin']will render every code block twice, once with the classec-theme-monokai, and once withec-theme-slack-ochin.
0.20.0
-
Adds
removeCommentsWhenCopyingTerminalFramesconfig option toplugin-frames. Thanks @AkashRajpurohit!If
true(which is the default), the “Copy to clipboard” button of terminal window frames will remove comment lines starting with#from the copied text.This is useful to reduce the copied text to the actual commands users need to run, instead of also copying explanatory comments or instructions.
0.19.2
- Adds support for Astro 3.0.0 incl. prereleases.
0.19.1
- Adds support for CSS variables to option
styleOverrides.terminalTitlebarDotsForeground. Thanks @delucis!
0.19.0
-
Adds support for
diff-like syntax andlangmeta attribute. Thanks for the idea @hirasso!To mark lines as inserted or deleted, you can now use the widely supported
difflanguage as an alternative to adding line numbers to the opening code fence.You can even specify a separate syntax highlighting language by adding a
lang="..."attribute to the opening fence. See README.md for more details.
0.18.1
- Fixes possible
querySelectorAll is not a functionissue on page content changes
0.18.0
-
Adds support for ANSI formatted code blocks. Thanks @fflaten!
You can now use the new language
ansito render code blocks containing ANSI escape sequences. This allows you to render colorful terminal output.
0.17.0
- Adds support for Windows drive letters and typical path patterns to file name comment detection. Thanks @fflaten!
0.16.0
-
Improves file type support when extracting file names from comments. Thanks @fflaten!
- Adds more file types to the
LanguageGroupsobject - Exports
LanguageGroupsto allow external modification - Extends automatic detection of frame type to differentiate between shell scripts and terminal sessions based on file name and/or shebang (if any)
- Adds more file types to the
0.15.0
- Synchronizes package versions to prevent future dependency issues.
0.14.0
-
Adds support to override frame types per code block. Thanks @Princesseuh!
By default, the plugin will automatically select the frame type (code editor or terminal) based on the language identifier in your code block’s opening fence.
You can override this behavior and force a specific frame type by adding an optional
frame="..."attribute after the language identifier.The supported values for this attribute are
code,terminal,noneandauto. The default value isauto.
0.13.0
-
Adds config options
useThemedScrollbarsanduseThemedSelectionColors. Thanks @Princesseuh!Both options default to
true. Set any of them tofalseto prevent themes from customizing their appearance and render them using the browser’s default style.
0.12.2
- Fixes non-working copy buttons in dynamically loaded content.
0.12.1
- Makes marked text selectable (#15). Thanks @hirasso!
0.12.0
- Fixes copy button on Firefox (still missing
:has()support).
0.11.0
-
Adds default export for
astro addsupport. -
Reduces potential of unexpected changes through site-wide CSS.
0.10.0
- Adds RTL support (ensure that code lines are always LTR).
0.9.1
-
Improves mobile core and copy button styles.
-
Enables stricter TypeScript checks (exactOptionalPropertyTypes), improves types.
0.9.0
- Adds tabWidth option to normalize tabs to spaces (default: 2).
0.8.4
- Fixes feedback tooltip on mobile Safari.
0.8.3
- Improves mobile core and copy button styles.
0.8.2
- Fixes CSS inconsistencies due to box-sizing.
0.8.1
- Makes
astropeer dependency more tolerant.
0.8.0
- Adds support for localized texts, adds German to frames plugin.
0.7.0
-
Introduces the first working version of the Astro integration package
astro-expressive-code. -
Adds custom renderer support.
0.6.0
-
Allows plugins to add JS modules.
-
Adds copy to clipboard button.
0.5.0
- Automatically trims whitespace at the end of lines, and removes empty lines at the beginning & end of code blocks.
0.4.2
- Turns off explanations to improve Shiki performance.
0.4.1
- Fixes issues with color transforms.
0.4.0
-
Provides access to all
expressive-codeexports. -
Changes base font size unit to rem.
-
Makes tab margins configurable, improves defaults.
-
Fixes incorrect highlighting of terminal placeholders.
0.3.0
- Synchronizes package versions.
0.2.0
- Initial release.