Math
The math extension adds support for mathematical equations in your document, including mathInline node for inline expressions and mathBlock node for block expressions. It is renderer agnostic, allowing you to use any math rendering library such as KaTeX or Temml.
<script setup lang="ts">
import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor, type NodeJSON } from 'prosekit/core'
import { ProseKit } from 'prosekit/vue'
import { sampleContent } from '../../sample/sample-doc-tex'
import { defineExtension } from './extension'
const props = defineProps<{
initialContent?: NodeJSON
}>()
const extension = defineExtension()
const defaultContent = props.initialContent ?? sampleContent
const editor = createEditor({ extension, defaultContent })
</script>
<template>
<ProseKit :editor="editor">
<div class="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<div class="relative w-full flex-1 box-border overflow-y-auto">
<div :ref="(el) => editor.mount(el as HTMLElement | null)" class="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500" />
</div>
</div>
</ProseKit>
</template>import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
import { defineMath } from 'prosekit/extensions/math'
import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex'
export function defineExtension() {
return union(defineBasicExtension(), defineMath({ renderMathBlock: renderKaTeXMathBlock, renderMathInline: renderKaTeXMathInline }))
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor.vue'import { render } from 'katex'
export function renderKaTeXMathBlock(text: string, element: HTMLElement) {
render(text, element, { displayMode: true, throwOnError: false, output: 'mathml' })
}
export function renderKaTeXMathInline(text: string, element: HTMLElement) {
render(text, element, { displayMode: false, throwOnError: false, output: 'mathml' })
}import type { NodeJSON } from 'prosekit/core'
const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0`
const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}`
export const sampleContent: NodeJSON = {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Inline equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: "Euler's identity " },
{ type: 'mathInline', content: [{ type: 'text', text: EULER_IDENTITY }] },
{ type: 'text', text: ' and the quadratic formula ' },
{ type: 'mathInline', content: [{ type: 'text', text: QUADRATIC_FORMULA }] },
{ type: 'text', text: ' can appear within text. Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$...$' },
{ type: 'text', text: ' to insert an inline equation.' },
],
},
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Block equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'The Gaussian integral:' },
],
},
{
type: 'mathBlock',
content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$$' },
{ type: 'text', text: ' in a new line and press Enter to create a block equation.' },
],
},
],
}<script lang="ts">
import 'prosekit/basic/style.css'
import 'prosekit/basic/typography.css'
import { createEditor, type NodeJSON } from 'prosekit/core'
import { ProseKit } from 'prosekit/svelte'
import { sampleContent } from '../../sample/sample-doc-tex'
import { defineExtension } from './extension'
const props: {
initialContent?: NodeJSON
} = $props()
const extension = defineExtension()
const defaultContent = props.initialContent ?? sampleContent
const editor = createEditor({ extension, defaultContent })
</script>
<ProseKit {editor}>
<div class="box-border h-full w-full min-h-36 overflow-y-hidden overflow-x-hidden rounded-md border border-solid border-gray-200 dark:border-gray-700 shadow-sm flex flex-col bg-white dark:bg-gray-950 text-black dark:text-white">
<div class="relative w-full flex-1 box-border overflow-y-auto">
<div {@attach editor.mount} class="ProseMirror box-border min-h-full px-[max(4rem,calc(50%-20rem))] py-8 outline-hidden outline-0 [&_span[data-mention=user]]:text-blue-500 [&_span[data-mention=tag]]:text-violet-500"></div>
</div>
</div>
</ProseKit>import { defineBasicExtension } from 'prosekit/basic'
import { union } from 'prosekit/core'
import { defineMath } from 'prosekit/extensions/math'
import { renderKaTeXMathBlock, renderKaTeXMathInline } from '../../sample/katex'
export function defineExtension() {
return union(defineBasicExtension(), defineMath({ renderMathBlock: renderKaTeXMathBlock, renderMathInline: renderKaTeXMathInline }))
}
export type EditorExtension = ReturnType<typeof defineExtension>export { default as ExampleEditor } from './editor.svelte'import { render } from 'katex'
export function renderKaTeXMathBlock(text: string, element: HTMLElement) {
render(text, element, { displayMode: true, throwOnError: false, output: 'mathml' })
}
export function renderKaTeXMathInline(text: string, element: HTMLElement) {
render(text, element, { displayMode: false, throwOnError: false, output: 'mathml' })
}import type { NodeJSON } from 'prosekit/core'
const EULER_IDENTITY = String.raw`e^{i\pi} + 1 = 0`
const QUADRATIC_FORMULA = String.raw`x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}`
const GAUSSIAN_INTEGRAL = String.raw`\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}`
export const sampleContent: NodeJSON = {
type: 'doc',
content: [
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Inline equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: "Euler's identity " },
{ type: 'mathInline', content: [{ type: 'text', text: EULER_IDENTITY }] },
{ type: 'text', text: ' and the quadratic formula ' },
{ type: 'mathInline', content: [{ type: 'text', text: QUADRATIC_FORMULA }] },
{ type: 'text', text: ' can appear within text. Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$...$' },
{ type: 'text', text: ' to insert an inline equation.' },
],
},
{
type: 'heading',
attrs: { level: 2 },
content: [{ type: 'text', text: 'Block equations' }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'The Gaussian integral:' },
],
},
{
type: 'mathBlock',
content: [{ type: 'text', text: GAUSSIAN_INTEGRAL }],
},
{
type: 'paragraph',
content: [
{ type: 'text', text: 'Type ' },
{ type: 'text', marks: [{ type: 'code' }], text: '$$' },
{ type: 'text', text: ' in a new line and press Enter to create a block equation.' },
],
},
],
}import Temml const Temml: Temml from 'temml'
import { defineMath function defineMath(options: MathOptions): MathExtension@public } from 'prosekit/extensions/math'
const extension const extension: MathExtension = defineMath function defineMath(options: MathOptions): MathExtension@public ({
renderMathInline MathOptions.renderMathInline: RenderMathInlineThe function to render the math inline. : (text text: string : string, element element: HTMLElement : HTMLElement) => {
// Render inline math into the given <span> element
Temml const Temml: Temml .render Temml.render(text: string, element: HTMLElement, options: {
displayMode: boolean;
}): void
(text text: string , element element: HTMLElement , { displayMode displayMode: boolean : false })
},
renderMathBlock MathOptions.renderMathBlock: RenderMathBlockThe function to render the math block. : (text text: string : string, element element: HTMLElement : HTMLElement) => {
// Render block math into the given <div> element
Temml const Temml: Temml .render Temml.render(text: string, element: HTMLElement, options: {
displayMode: boolean;
}): void
(text text: string , element element: HTMLElement , { displayMode displayMode: boolean : true })
},
})Keyboard Interaction
Section titled “Keyboard Interaction”Type $...$ to create an inline math expression.
Type $$ on an empty line and press Enter to create a block-level math expression.