npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@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

Readme

Vue Math Editor

A Vue 3 component for rich text editing with math formula support using MathLive

npm version License: MIT

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-editor

Basic 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, style
  • data-latex (for formula storage)
  • contenteditable, readonly, value

Protection Features

  • Automatic Sanitization: All getHTMLContent() and loadContent() 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 maxLength prop 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.