Custom Code Block Theme & Language
To configure a code block highlighting theme and language, you can extend the editor's default schema with a new codeBlock
, which you can pass options into when creating. You can then use a shiki highlighter to add custom syntax highlighting.
First use the shiki-codegen CLI to create a shiki.bundle.ts
file. You can then pass this file into the codeBlock
options when creating it.
Relevant Docs:
import { BlockNoteSchema, createCodeBlockSpec } from "@blocknote/core";
import "@blocknote/core/fonts/inter.css";
import { BlockNoteView } from "@blocknote/mantine";
import "@blocknote/mantine/style.css";
import { useCreateBlockNote } from "@blocknote/react";
// Bundle created from `npx shiki-codegen --langs typescript,javascript,react --themes light-plus,dark-plus --engine javascript --precompiled ./shiki.bundle.ts`
import { createHighlighter } from "./shiki.bundle";
export default function App() {
// Creates a new editor instance.
const editor = useCreateBlockNote({
schema: BlockNoteSchema.create().extend({
blockSpecs: {
codeBlock: createCodeBlockSpec({
indentLineWithTab: true,
defaultLanguage: "typescript",
supportedLanguages: {
typescript: {
name: "TypeScript",
aliases: ["ts"],
},
javascript: {
name: "JavaScript",
aliases: ["js"],
},
vue: {
name: "Vue",
},
},
// This creates a highlighter, it can be asynchronous to load it afterwards
createHighlighter: () =>
createHighlighter({
themes: ["dark-plus", "light-plus"],
langs: [],
}),
}),
},
}),
initialContent: [
{
type: "codeBlock",
props: {
language: "typescript",
},
content: [
{
type: "text",
text: "const x = 3 * 4;",
styles: {},
},
],
},
{
type: "paragraph",
},
{
type: "heading",
props: {
textColor: "default",
backgroundColor: "default",
textAlignment: "left",
level: 3,
},
content: [
{
type: "text",
text: 'Click on "Typescript" above to see the different supported languages',
styles: {},
},
],
},
{
type: "paragraph",
},
],
});
// Renders the editor instance using a React component.
return <BlockNoteView editor={editor} />;
}
/* Generate by @shikijs/codegen */
import type {
DynamicImportLanguageRegistration,
DynamicImportThemeRegistration,
HighlighterGeneric,
} from "@shikijs/types";
import { createdBundledHighlighter } from "@shikijs/core";
import { createJavaScriptRegexEngine } from "@shikijs/engine-javascript";
type BundledLanguage = "typescript" | "ts" | "javascript" | "js" | "vue";
type BundledTheme = "light-plus" | "dark-plus";
type Highlighter = HighlighterGeneric<BundledLanguage, BundledTheme>;
const bundledLanguages = {
typescript: () => import("@shikijs/langs-precompiled/typescript"),
ts: () => import("@shikijs/langs-precompiled/typescript"),
javascript: () => import("@shikijs/langs-precompiled/javascript"),
js: () => import("@shikijs/langs-precompiled/javascript"),
vue: () => import("@shikijs/langs-precompiled/vue"),
} as Record<BundledLanguage, DynamicImportLanguageRegistration>;
const bundledThemes = {
"light-plus": () => import("@shikijs/themes/light-plus"),
"dark-plus": () => import("@shikijs/themes/dark-plus"),
} as Record<BundledTheme, DynamicImportThemeRegistration>;
const createHighlighter = /* @__PURE__ */ createdBundledHighlighter<
BundledLanguage,
BundledTheme
>({
langs: bundledLanguages,
themes: bundledThemes,
engine: () => createJavaScriptRegexEngine(),
});
export { createHighlighter };
export type { BundledLanguage, BundledTheme, Highlighter };