Skip to content

Editor & Terminal Frames

Expressive Code supports rendering frames around your code blocks. By default, the type of frame (editor window or terminal window) is selected automatically based on the language identifier in your code block’s opening fence.

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.

Usage in markdown / MDX

Code editor frames

To make code blocks look like an editor window similar to VS Code, you must provide a file name that can be displayed in the open file tab.

To do this, you can either set the title attribute in the opening code fence to a file name, or add a file name comment to the first lines of the code.

See the markdown code below for examples of both methods:

editor-example.md
```js title="my-test-file.js"
console.log('Title attribute example')
```
```html
<!-- src/content/index.html -->
<div>File name comment example</div>
```

The rendered result looks like this:

my-test-file.js
console.log('Title attribute example')
src/content/index.html
<div>File name comment example</div>

Terminal frames

When encountering code blocks with a language identifier that is typically used for terminal sessions or shell scripts (ansi, bash, bat, batch, cmd, console, powershell, ps, ps1, psd1, psm1, sh, shell, shellscript, shellsession, zsh), Expressive Code performs additional checks to detect the frame type to use:

  • If the code block contains a shell script file name in the title attribute of the opening code fence or a file name comment, or if the code starts with a shebang (#!), it is considered to be a script file instead of a terminal session, and is rendered with a code editor frame if a file name was provided, or as a plain code block otherwise.
  • In all other cases, the code block is considered to be a terminal session and rendered with a terminal frame.

In contrast to code editor frames, terminal frames do not require a title. The title bar will always be rendered, and you can optionally add a title using the title attribute:

```bash
echo "This terminal frame has no title"
```
```powershell title="PowerShell terminal example"
Write-Output "This one has a title!"
```

The rendered result looks like this:

Terminal window
echo "This frame has no title"
PowerShell terminal example
Write-Output "This one has a title!"

File name comments

If a code block does not have a title attribute, Expressive Code supports automatically extracting a title from a file name comment inside your code.

The following conditions must be met for a comment to be recognized as a file name comment:

  • It must appear within the first 4 lines of the code block.
  • Its line must start with //, <!--, /* or #, but not #!. Although not required, we recommend using the comment syntax matching your code block’s language.
  • It can optionally have a prefix that ends with a colon (:). This allows you to prefix the file name with some text: // File name: index.js
  • The file name appears to be valid in the context of the code block’s language. For example, a comment containing a CSS file name in a JavaScript code block will be ignored.

Once a file name comment is found, it is removed from the code block’s content, and the extracted file name is used as the code block’s title.

Overriding frame types

If you want to override the automatic frame type detection for some code blocks, you can add the frame="..." attribute to the opening code fence.

The supported values for this attribute are code, terminal, none and auto. The default value is auto.

```sh frame="none"
echo "Look ma, no frame!"
```
```ps frame="code" title="PowerShell Profile.ps1"
# Without overriding, this would be a terminal frame
function Watch-Tail { Get-Content -Tail 20 -Wait $args }
New-Alias tail Watch-Tail
```

The rendered result looks like this:

echo "Look ma, no frame!"
PowerShell Profile.ps1
# Without overriding, this would be a terminal frame
function Watch-Tail { Get-Content -Tail 20 -Wait $args }
New-Alias tail Watch-Tail

Usage in the <Code> component

The frames plugin adds multiple props to the <Code> component that allow direct access to its features. The following props are available:

Props

frame

Type: "terminal" | "code" | "none" | "auto" Default: auto

Allows you to override the automatic frame type detection for a code block.

The supported values are code, terminal, none and auto.

title

Type: string

The code block’s title. For terminal frames, this is displayed as the terminal window title, and for code frames, it’s displayed as the file name in an open file tab.

If no title is given, the plugin will try to automatically extract a title from a file name comment inside your code, unless disabled by the extractFileNameFromCode option.

Configuration

When using this plugin through a framework integration, you can configure it by passing options to the integration.

In addition, you can also override its default styles by adding a frames object to the styleOverrides engine config option. You can find a list of all overridable styles below.

Here are configuration examples for some popular site generators:

astro.config.mjs
import { defineConfig } from 'astro/config'
import astroExpressiveCode from 'astro-expressive-code'
export default defineConfig({
integrations: [
astroExpressiveCode({
// You can optionally override the plugin's default settings here
frames: {
// Example: Hide the "Copy to clipboard" button
showCopyToClipboardButton: false,
},
styleOverrides: {
// You can optionally override the plugin's default styles here
frames: {
shadowColor: '#124',
},
},
}),
],
})

Available plugin options

You can configure the plugin’s features using the following options:

extractFileNameFromCode

Type: boolean Default: true

If true, 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.

removeCommentsWhenCopyingTerminalFrames

Type: boolean Default: true

If true, 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.

showCopyToClipboardButton

Type: boolean Default: true

If true, a “Copy to clipboard” button will be shown for each code block.

Available style overrides

This plugin adds a frames object to the styleOverrides engine config option, allowing you to customize the visual appearance of the rendered frames. The object contains the following properties:

editorActiveTabBackground

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['tab.activeBackground']

The CSS background value for the active editor tab.

editorActiveTabBorderColor

Type: UnresolvedStyleValue Default: 'transparent'

The border color of the active editor tab.

editorActiveTabForeground

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['tab.activeForeground']

The foreground color of the active editor tab.

editorActiveTabIndicatorBottomColor

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['tab.activeBorder']

The color of the indicator line displayed at the bottom border of the active editor tab.

editorActiveTabIndicatorHeight

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('borderWidth')

The height of the indicator lines highlighting the active editor tab. These are colorful lines that appear at the top and/or bottom of the active tab.

The individual line colors can be set in editorActiveTabIndicatorTopColor and editorActiveTabIndicatorBottomColor.

editorActiveTabIndicatorTopColor

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['tab.activeBorderTop']

The color of the indicator line displayed at the top border of the active editor tab.

editorBackground

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('codeBackground')

The background color of the code editor. This color is used for the “code” frame type.

editorTabBarBackground

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['editorGroupHeader.tabsBackground']

The CSS background value of the editor tab bar.

editorTabBarBorderBottomColor

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['editorGroupHeader.tabsBorder'] || 'transparent'

The color of the bottom border of the editor tab bar. This is an additional border that can be used to display a line between the editor tab bar and the code contents.

editorTabBarBorderColor

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('borderColor')

The border color of the editor tab bar.

editorTabBorderRadius

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('borderRadius')

The border radius to apply to the outer corners of editor tabs.

editorTabsMarginBlockStart

Type: UnresolvedStyleValue Default: '0'

The block margin (= top margin in horizontal writing mode) to apply inside the tab bar before the editor tabs.

editorTabsMarginInlineStart

Type: UnresolvedStyleValue Default: '0'

The inline margin (= left margin in horizontal writing mode) to apply inside the tab bar before the first editor tab.

frameBoxShadowCssValue

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => `0.1rem 0.1rem 0.2rem ${resolveSetting('frames.shadowColor')}`

The CSS value for the box shadow of the frame.

inlineButtonBackground

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('frames.inlineButtonForeground')

The background color of the copy button. This color is modified by the state-dependent opacity values specified in inlineButtonBackgroundIdleOpacity, inlineButtonBackgroundHoverOrFocusOpacity and inlineButtonBackgroundActiveOpacity.

inlineButtonBackgroundActiveOpacity

Type: UnresolvedStyleValue Default: '0.3'

The opacity of the copy button background when pressed.

inlineButtonBackgroundHoverOrFocusOpacity

Type: UnresolvedStyleValue Default: '0.2'

The opacity of the copy button background when hovered or focused.

inlineButtonBackgroundIdleOpacity

Type: UnresolvedStyleValue Default: '0'

The opacity of the copy button background when idle.

inlineButtonBorder

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('frames.inlineButtonForeground')

The border color of the copy button.

inlineButtonBorderOpacity

Type: UnresolvedStyleValue Default: '0.4'

The opacity of the copy button border.

inlineButtonForeground

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('codeForeground')

The foreground color of the copy button.

shadowColor

Type: UnresolvedStyleValue Default: ({ theme, resolveSetting }) => theme.colors['widget.shadow'] || multiplyAlpha(resolveSetting('borderColor'), 0.75)

The color to use for the shadow of the frame.

terminalBackground

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['terminal.background']

The background color of the terminal window. This color is used for the “terminal” frame type.

terminalTitlebarBackground

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['titleBar.activeBackground'] || theme.colors['editorGroupHeader.tabsBackground']

The background color of the terminal title bar.

terminalTitlebarBorderBottomColor

Type: UnresolvedStyleValue Default: theme.colors['titleBar.border'] || onBackground(resolveSetting('borderColor'), theme.type === 'dark' ? '#000000bf' : '#ffffffbf')

The color of the border between the terminal title bar and the terminal contents.

terminalTitlebarDotsForeground

Type: UnresolvedStyleValue Default: ({ resolveSetting }) => resolveSetting('frames.terminalTitlebarForeground')

The color of the three dots in the terminal title bar.

terminalTitlebarDotsOpacity

Type: UnresolvedStyleValue Default: '0.15'

The opacity of the three dots in the terminal title bar.

terminalTitlebarForeground

Type: UnresolvedStyleValue Default: ({ theme }) => theme.colors['titleBar.activeForeground']

The foreground color of the terminal title bar.

tooltipSuccessBackground

Type: UnresolvedStyleValue Default: ({ theme }) => setLuminance(theme.colors['terminal.ansiGreen'] || '#0dbc79', 0.18)

The background color of the tooltip shown after successfully copying the code.

tooltipSuccessForeground

Type: UnresolvedStyleValue Default: 'white'

The foreground color of the tooltip shown after successfully copying the code.