Skip to content

Code Block

The Code Block app adds a field type for writing and storing code snippets. The field returns a JSON object holding the code, the selected language, the highlight states, the title, and the line number offset. Render that object with a syntax highlighter such as highlight.js or CodeMirror.

  • Write code in a dedicated editor field.
  • Select the language of the snippet.
  • Add a title to the snippet.
  • Offset the first line number.
  • Highlight individual lines with configurable states.

In the Block Library, select the block you want to edit, add a field, set its field type to Plugin, and set the custom type to storyblok-code-block.

The field takes the following optional options:

Option Type Description
enableTitle Boolean To show the title input, set to true. The field stores the title in content.title.
languages JSON Array of language strings offered in the language selector. Without this option, the field hides the language selector.
enableLineNumberStart Boolean To show the input that offsets the first line number, set to true. The field stores the offset in content.lineNumberStart.
highlightStates JSON Array of at least two objects with a value and a color, used to highlight lines. Without this option, line highlighting is off.

Example languages value:

["Ada", "Bash", "C", "Dart", "Elm", "F#", "Haskell", "JavaScript", "JSON", "TypeScript"]

Example highlightStates value:

[
{
"value": "",
"color": "transparent"
},
{
"value": "attention",
"color": "#fbce41"
},
{
"value": "add",
"color": "#2db47d"
},
{
"value": "remove",
"color": "#ff6159"
}
]

The Visual Editor uses color to highlight lines, and the content uses value to track which lines an editor highlighted. Lines aren’t highlighted by default and hold an empty string ("").

With the highlightStates configuration from the previous example, the field returns the following object:

{
"code": "\"output\": {\n \"dest\": \"./dist/index.js\",\n \"dest\": \"./dist/index.cjs\",\n \"types\": \"./dist/types.d.ts\",\n}",
"highlightStates": ["", "remove", "add", "", ""],
"title": "myfile.json",
"language": "json",
"lineNumberStart": 10
}

All properties except code are optional.

Each enabled feature (title, line highlighting, language, and line number offset) needs a matching implementation in the frontend. The examples below demonstrate the approach with highlight.js and CodeMirror; adapt them to the library versions you use.

Highlight.js requires a plugin for line numbers, such as highlightjs-line-numbers.js. Store the pre root element in highlightJsRoot and the field value in content, and add a class to each highlighted line:

highlightJsRoot.querySelectorAll("tbody > tr").forEach((rowElement, rowIndex) => {
const highlightState = content.highlightStates[rowIndex];
if (highlightState === "") {
return;
}
const className = `code-block__row--${highlightState}`;
rowElement.classList.add(className);
});

For example, with the following content, the first line receives the class code-block__row--add and the second line remains the same:

{
"code": "console.log(1)\nconsole.log(1)",
"highlightStates": ["add", ""]
}

Style the classes in your CSS file:

.code-block__row--attention {
background-color: #fbce4190;
}
.code-block__row--add {
background-color: #2db47d90;
}
.code-block__row--remove {
background-color: #ff615990;
}

The app uses CodeMirror. To render the code, enable read-only mode and line number gutters, where content is the field value:

import { EditorView, lineNumbers } from "@codemirror/view";
import { EditorState } from "@codemirror/state";
new EditorView({
doc: content.code,
extensions: [EditorState.readOnly.of(true), lineNumbers()],
});

Use a CSS-in-JS library to generate styles with the :nth-of-type() selector, where colorFromHighlightState maps each entry of content.highlightStates to a color:

css(
content.highlightStates.map((highlightState, rowIndex) => ({
[`.cm-line:nth-of-type(${rowIndex + 1})`]: {
backgroundColor: colorFromHighlightState(highlightState),
},
}))
);

This method uses server-side rendering while maintaining the DOM nodes in their original state.

Was this page helpful?

What went wrong?

This site uses reCAPTCHA and Google's Privacy Policy (opens in a new window).Terms of Service (opens in a new window) apply.