Example: katex
Math equation rendering using the KaTeX library.
Install this example with
shadcn: npx shadcn@latest add @prosekit/vue-example-katexnpx shadcn@latest add @prosekit/svelte-example-katex<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.' },
],
},
],
}