@expressive-code/plugin-frames
Contents
What is this?
A default plugin of Expressive Code, an engine for presenting source code on the web.
It renders a window frame around every code block. Depending on the code's language, this frame can look like a code editor (similar to VS Code), or like a terminal window.
Frames can have optional titles, which are either taken from the code block's meta string, or from a file name comment in the first lines of the code.
When should I use this?
You can use this plugin to render a window frame around your code blocks. For more information, see the usage examples below.
This plugin is installed by default by our higher-level packages like remark-expressive-code
, so you can start using it in markdown / MDX documents without having to install it first.
Installation (not required)
No installation is required. This package is installed by default by our higher-level packages.
If you are using the core package directly (e.g. because you are writing an integration), see the Advanced use cases section for more information.
Usage in markdown / MDX documents
If you are using a higher-level integration package like remark-expressive-code
, frames will automatically be rendered around your code blocks in markdown / MDX documents.
The type of frame that will be rendered (editor window or terminal window) is selected automatically based on the language identifier in your code block's opening fence:
Code editor window frames
Code blocks will be rendered as a code editor window if their language identifier is not a terminal language (see next section for a list of terminal languages):
```js
console.log('Hello World!')
```
Terminal window frames
Code blocks will be rendered as a terminal window if their language identifier matches one of the supported terminal languages bash
, shellscript
, shell
, sh
, or zsh
:
```bash
npm install
```
Adding titles (open file tab or terminal window title)
You can give your frames a title by adding an optional title="...your title..."
attribute after the language identifier.
The following code block will be rendered as an editor window with an open file tab named my-test-file.js
:
```js title="my-test-file.js"
console.log('Hello World!')
```
Unless turned off in the plugin configuration, you can also add a file name comment in the first lines of your code to set the title. This comment will be removed from the code and shown as the frame's title instead:
```js
// my-test-file.js
console.log('Hello World!')
```
Configuration
When using this plugin through higher-level integration packages, you can configure it by passing options to the higher-level package.
As it's most likely that you are using remark-expressive-code
, here are configuration examples for some popular site generators:
Astro configuration example
import { defineConfig } from 'astro/config'
import remarkExpressiveCode from 'remark-expressive-code'
const remarkExpressiveCodeOptions = {
frames: {
styleOverrides: {
editorTabBarBackground: ({ theme }) => theme.colors['menu.background'],
shadowColor: 'purple',
},
},
}
export default defineConfig({
markdown: {
remarkPlugins: [
[remarkExpressiveCode, remarkExpressiveCodeOptions],
],
},
})
Next.js configuration example using @next/mdx
import createMDX from '@next/mdx'
import remarkExpressiveCode from 'remark-expressive-code'
const remarkExpressiveCodeOptions = {
frames: {
styleOverrides: {
editorTabBarBackground: ({ theme }) => theme.colors['menu.background'],
shadowColor: 'purple',
},
},
}
const nextConfig = {
reactStrictMode: true,
pageExtensions: ["js", "jsx", "ts", "tsx", "md", "mdx"],
}
const withMDX = createMDX({
extension: /\.mdx?$/,
options: {
remarkPlugins: [
[remarkExpressiveCode, remarkExpressiveCodeOptions],
],
rehypePlugins: [],
},
})
export default withMDX(nextConfig)
Available plugin options
You can pass the following options to the plugin:
-
extractFileNameFromCode: boolean
If true
(which is the default), and no title was found in the code block's meta string, the plugin will try to find and extract a comment line containing the code block file name from the first 4 lines of the code.
-
styleOverrides
Allows overriding the plugin's default styles using an object with named properties.
The property values can either be a string, or a function that returns a string. If a function is used, it will be called with the following arguments:
-
theme
: An ExpressiveCodeTheme object containing the current theme's colors and other properties.
-
coreStyles
: An object containing the ExpressiveCodeEngine core styles.
-
resolveSetting
: A function that can be used to resolve another style setting. It takes a style property name, and returns its resolved value. For example, frameBoxShadowCssValue
uses it to include the shadowColor
value:
styleOverrides: {
frameBoxShadowCssValue: ({ resolveSetting }) =>
`0.1rem 0.1rem 0.2rem ${resolveSetting('shadowColor')}`
}
The following properties are available:
-
General styles: shadowColor
, frameBoxShadowCssValue
-
Editor styles:
editorActiveTabBackground
, editorActiveTabForeground
, editorActiveTabBorderTop
, editorActiveTabBorderBottom
, editorTabBorderRadius
, editorTabBarBackground
, editorTabBarBorderColor
, editorTabBarBorderBottom
, editorBackground
-
Terminal styles:
terminalTitlebarDotsForeground
, terminalTitlebarBackground
, terminalTitlebarForeground
, terminalTitlebarBorderBottom
, terminalBackground
Advanced use cases
Manual installation
You only need to install this plugin if you are using the core package @expressive-code/core
directly. In this case, you can install the plugin like this:
npm install @expressive-code/plugin-frames
Manual usage from the core package
Warning:
This is an advanced usage example! You normally don't need to use the core package directly, or manually add this plugin to the configuration.
import { ExpressiveCodeEngine } from '@expressive-code/core'
import { pluginFrames } from '@expressive-code/plugin-frames'
const ec = new ExpressiveCodeEngine({
plugins: [
pluginFrames(),
],
})
const code = `
// my-test-file.js
const hello = 'World!'
`
const renderResult = await ec.render({
code: code.trim(),
language: 'js',
})
console.log(renderResult.renderedGroupContents[0].codeBlock.code)