@fengrui-tec/vue-math-editor
v1.0.0
Published
A Vue 3 component for rich text editing with math formula support using MathLive
Downloads
128
Maintainers
Readme
Vue Math Editor
A Vue 3 component for rich text editing with math formula support using MathLive
Features
- 📝 Rich text editing (bold, italic, underline, strikethrough)
- 🔢 Visual math formula editor using MathLive with symbol panels
- 🎨 WYSIWYG formula editing experience
- ⌨️ Keyboard shortcuts for common operations
- ↩️ Undo/redo support with configurable history size
- 🔒 Built-in XSS protection with DOMPurify sanitization
- 📏 Optional content length limit
- 🎯 Full TypeScript support
- 🔧 Fully customizable via slots and props
- 📦 Lightweight and tree-shakeable
- 🖱️ Click on formulas to edit them
Installation
npm install @fengrui-tec/vue-math-editor
# or
yarn add @fengrui-tec/vue-math-editor
# or
pnpm add @fengrui-tec/vue-math-editorBasic Usage
Global Registration
import { createApp } from 'vue'
import VueMathEditor from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const app = createApp(App)
app.use(VueMathEditor)style.css includes the MathLive font assets required for correct radical,
fraction, and superscript/subscript rendering. If formulas look different after
integration, check for missing KaTeX_*.woff2 requests in the browser network panel.
Component Usage
<template>
<MathEditor
v-model="content"
placeholder="在此输入文字和公式..."
:show-format-toolbar="true"
@update:modelValue="handleUpdate"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MathEditor } from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const content = ref('<p>欢迎使用数学编辑器!</p>')
const handleUpdate = (value: string) => {
console.log('Content updated:', value)
}
</script>Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| modelValue | string | '' | v-model bound content (HTML) |
| placeholder | string | '在此输入文字和公式...' | Placeholder text |
| showFormatToolbar | boolean | true | Show format toolbar |
| showClearButton | boolean | true | Show clear button |
| showFontSize | boolean | true | Show font size selector |
| showAlignment | boolean | true | Show alignment buttons |
| showLists | boolean | true | Show list buttons |
| showFormulaCount | boolean | true | Show formula count in status bar |
| showHelp | boolean | true | Show help panel |
| maxHistorySize | number | 50 | Maximum history entries |
| maxLength | number | undefined | Maximum content length (characters) |
Events
| Event | Payload | Description |
|-------|---------|-------------|
| update:modelValue | string | Emitted when content changes |
| max-length-exceeded | - | Emitted when content exceeds maxLength |
Slots
<MathEditor v-model="content">
<!-- Custom toolbar -->
<template #toolbar>
<CustomToolbar @insert="handleInsert" />
</template>
<!-- Custom format toolbar -->
<template #format-toolbar>
<CustomFormatToolbar @format="handleFormat" />
</template>
<!-- Custom status bar -->
<template #status-bar="{ formulaCount, lastSaved }">
<CustomStatusBar :count="formulaCount" :saved="lastSaved" />
</template>
<!-- Custom modal -->
<template #modal>
<CustomFormulaModal v-model="showModal" @confirm="handleConfirm" />
</template>
<!-- Custom help panel -->
<template #help>
<CustomHelpPanel />
</template>
</MathEditor>Keyboard Shortcuts
| Shortcut | Action |
|----------|--------|
| Ctrl + B | Bold |
| Ctrl + I | Italic |
| Ctrl + U | Underline |
| Ctrl + = | Insert formula |
| Ctrl + Z | Undo |
| Ctrl + Y | Redo |
Exposed Methods
The MathEditor component exposes the following methods that you can call via template ref:
| Method | Parameters | Description |
|--------|------------|-------------|
| insertFormula() | - | Open formula modal to insert a new formula |
| clearAll() | - | Clear all editor content (with confirmation) |
| getContent() | - | Get current HTML content |
| setContent(content) | content: string | Set editor content |
Example using exposed methods:
<template>
<MathEditor
ref="editorRef"
v-model="content"
/>
<button @click="insertNewFormula">Insert Formula</button>
<button @click="clearEditor">Clear All</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MathEditor } from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const content = ref('')
const editorRef = ref<InstanceType<typeof MathEditor> | null>(null)
const insertNewFormula = () => {
editorRef.value?.insertFormula()
}
const clearEditor = () => {
editorRef.value?.clearAll()
}
</script>import { useHistory, useFormula, useContent, useKeyboard } from '@fengrui-tec/vue-math-editor'
// History management
const { save, undo, redo, canUndo, canRedo } = useHistory({
maxSize: 50,
editorRef,
loadContent: (content) => { /* ... */ }
})
// Formula operations
const { createFormulaNode, insertAtCursor } = useFormula({
editorRef,
isEmpty: computed(() => /* ... */)
})
// Content management
const { getHTMLContent, loadContent, updateValue } = useContent({
editorRef,
emit: (event, value) => { /* ... */ }
})
// Keyboard shortcuts
const { handleKeydown, getShortcutHelp } = useKeyboard({
formatText: (cmd, val) => { /* ... */ },
undo: () => { /* ... */ },
redo: () => { /* ... */ }
})Individual Components
FormulaModal
The FormulaModal component provides a full-featured formula editing interface with symbol panels and LaTeX preview.
Props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| modelValue | boolean | false | Controls modal visibility (v-model) |
| latex | string | '' | Initial LaTeX formula |
| title | string | '编辑公式' | Modal title |
| confirmText | string | '确定' | Confirm button text |
| cancelText | string | '取消' | Cancel button text |
Events:
| Event | Payload | Description |
|-------|---------|-------------|
| update:modelValue | boolean | Emitted when modal opens/closes |
| update:latex | string | Emitted when LaTeX changes |
| confirm | latex: string | Emitted when user confirms |
| cancel | - | Emitted when user cancels |
Features:
- 📋 Symbol panels: Basic, Greek, Operations, Calculus, Sets, Arrows
- ↶️ Undo/Redo support for formula editing
- 🗑️ Clear button
- 📋 Copy LaTeX code button
- 🎨 Real-time LaTeX preview
Example:
<template>
<FormulaModal
v-model="showModal"
v-model:latex="currentFormula"
title="Custom Title"
confirm-text="Add"
cancel-text="Close"
@confirm="handleConfirm"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { FormulaModal } from '@fengrui-tec/vue-math-editor'
const showModal = ref(false)
const currentFormula = ref('')
const handleConfirm = (latex: string) => {
console.log('Formula confirmed:', latex)
showModal.value = false
}
</script>Other Components
You can also import other individual components:
<script setup lang="ts">
import { FormulaToolbar, FormatToolbar, StatusBar } from '@fengrui-tec/vue-math-editor'
</script>
<template>
<FormulaToolbar
:show-clear="true"
@insert="handleInsert"
@undo="undo"
@redo="redo"
@clear="clearAll"
/>
<FormatToolbar
:show-font-size="true"
:show-alignment="true"
:show-lists="true"
@format="handleFormat"
/>
<StatusBar
:formula-count="formulaCount"
:last-saved="lastSaved"
:show-formula-count="true"
/>
</template>TypeScript Support
This package is written in TypeScript and includes full type definitions:
import type {
MathEditorProps,
FormulaNode,
HistoryReturn,
UseFormulaReturn
} from '@fengrui-tec/vue-math-editor'Usage Examples
Example 1: Basic Editor with Custom Toolbar
<template>
<MathEditor
v-model="content"
placeholder="Start typing..."
:show-format-toolbar="true"
:show-clear-button="true"
@update:modelValue="handleUpdate"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MathEditor } from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const content = ref('<p>Welcome to the editor!</p>')
const handleUpdate = (value: string) => {
console.log('Content updated:', value)
// Save to backend, etc.
}
</script>Example 2: Editor with Content Length Limit
<template>
<MathEditor
v-model="content"
:max-length="5000"
@max-length-exceeded="handleMaxLengthExceeded"
/>
<p v-if="showWarning" class="warning">
Content exceeds maximum length (5000 characters)!
</p>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MathEditor } from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const content = ref('')
const showWarning = ref(false)
const handleMaxLengthExceeded = () => {
showWarning.value = true
setTimeout(() => { showWarning.value = false }, 3000)
}
</script>Example 3: Custom Slots
<template>
<MathEditor v-model="content">
<!-- Custom toolbar without clear button -->
<template #toolbar="{ insert, undo, redo }">
<div class="my-toolbar">
<button @click="insert">Insert Formula</button>
<button @click="undo">Undo</button>
<button @click="redo">Redo</button>
</div>
</template>
<!-- Custom status bar -->
<template #status-bar="{ formulaCount, lastSaved }">
<div class="my-status">
Formulas: {{ formulaCount }} | Last saved: {{ lastSaved }}
</div>
</template>
</MathEditor>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MathEditor } from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const content = ref('')
</script>Example 4: Using Individual Components
<template>
<div class="my-editor">
<FormulaToolbar
:show-clear="false"
@insert="handleInsert"
@undo="undo"
@redo="redo"
/>
<MathEditor
ref="editorRef"
v-model="content"
placeholder="Type here..."
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { FormulaToolbar, MathEditor } from '@fengrui-tec/vue-math-editor'
import '@fengrui-tec/vue-math-editor/style.css'
const content = ref('')
const handleInsert = () => {
// Custom insert logic
}
const undo = () => {
// Custom undo logic
}
const redo = () => {
// Custom redo logic
}
</script>Security Features
This editor includes built-in security features to protect against XSS attacks:
Content Sanitization
All content is automatically sanitized using DOMPurify before being saved or retrieved.
Allowed HTML Tags:
- Text:
P,STRONG,EM,U,S,STRIKE - Structure:
UL,OL,LI,DIV,BLOCKQUOTE,BR - Formula:
MATH-FIELD,SPAN
Allowed Attributes:
class,id,styledata-latex(for formula storage)contenteditable,readonly,value
Protection Features
- ✅ Automatic Sanitization: All
getHTMLContent()andloadContent()operations pass through DOMPurify - ✅ Safe Loading: When loading content from external sources, it's sanitized before rendering
- ✅ Error Recovery: Graceful fallback for corrupted or invalid content
- ✅ Math Field Initialization: Safe re-initialization of math-field elements after content loads
- ✅ Length Limiting: Optional
maxLengthprop to prevent excessive content (counts text characters, not HTML)
Example with Security Options
<template>
<MathEditor
v-model="content"
:max-length="10000"
@max-length-exceeded="handleMaxLength"
/>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { MathEditor } from '@fengrui-tec/vue-math-editor'
const content = ref('')
const handleMaxLength = () => {
alert('Content exceeds maximum length!')
}
</script>Browser Support
- Chrome/Edge 90+
- Firefox 88+
- Safari 14+
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
