Skip to content

lingpotool/vue-markdown

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vue-markdown

MIT License

English | 中文

Vue 3 port of react-markdown (v10.1.0) - render Markdown as Vue components using the unified / remark / rehype ecosystem.

AI-Generated Project: This project was entirely generated by AI (Kiro AI IDE with Claude). The code, tests, and documentation were all produced through AI-assisted development. While thoroughly tested (58 tests, including property-based tests), please review the code before using in production.

What is this?

This library is a faithful 1:1 translation of react-markdown to Vue 3. It converts Markdown text to Vue VNodes using the same unified pipeline, so you get the same features, the same plugin ecosystem, and the same behavior - just for Vue.

Translation approach

react-markdown vue-markdown Notes
react/jsx-runtime vue/jsx-runtime Vue 3.3+ built-in
Markdown (function component) VueMarkdown (defineComponent) Synchronous rendering
MarkdownAsync (async component) VueMarkdownAsync (defineAsyncComponent) Use with <Suspense>
MarkdownHooks (hooks component) VueMarkdownHooks (defineComponent) ref + watchEffect
unreachable() from devlop throw new Error() No extra dependency
- elementAttributeNameCase: 'html' Required for Vue JSX runtime

Install

npm install git+https://github.com/lingpotool/vue-markdown.git

Or with pnpm:

pnpm add git+https://github.com/lingpotool/vue-markdown.git

Peer dependency: Vue >= 3.3.0

Use

Basic (synchronous)

<script setup>
import VueMarkdown from 'vue-markdown'
</script>

<template>
  <VueMarkdown children="# Hello, *world*!" />
</template>

With plugins

<script setup>
import VueMarkdown from 'vue-markdown'
import remarkGfm from 'remark-gfm'

const plugins = [remarkGfm]
</script>

<template>
  <VueMarkdown
    children="| Feature | Status |\n|---|---|\n| Tables | OK |"
    :remarkPlugins="plugins"
  />
</template>

Async (with <Suspense>)

<script setup>
import { VueMarkdownAsync } from 'vue-markdown'
import { markRaw } from 'vue'

const AsyncMd = markRaw(VueMarkdownAsync({
  children: '# Async content',
  remarkPlugins: [/* async plugins */]
}))
</script>

<template>
  <Suspense>
    <component :is="AsyncMd" />
    <template #fallback>Loading...</template>
  </Suspense>
</template>

Hooks (reactive async)

<script setup>
import { VueMarkdownHooks } from 'vue-markdown'
import { ref } from 'vue'

const md = ref('# Hello')
</script>

<template>
  <VueMarkdownHooks :children="md">
    <template #fallback>Loading...</template>
  </VueMarkdownHooks>
</template>

API

VueMarkdown (default export)

Synchronous component. Props:

Prop Type Default Description
children string '' Markdown content
remarkPlugins Array null remark plugins
rehypePlugins Array null rehype plugins
remarkRehypeOptions Object null Options for remark-rehype
components Object null Map tag names to Vue components
allowedElements string[] null Only allow these elements
disallowedElements string[] null Disallow these elements
allowElement Function null Filter function for elements
unwrapDisallowed boolean false Unwrap disallowed elements (keep children)
skipHtml boolean false Skip HTML in Markdown
urlTransform Function | null defaultUrlTransform Transform URLs; pass null to skip

VueMarkdownAsync(options)

Factory function that returns an async component. Same options as VueMarkdown. Use with <Suspense>.

VueMarkdownHooks

Reactive async component. Same props as VueMarkdown plus:

Prop Type Default Description
fallback VNode null Content to show while loading

Also supports a #fallback slot.

defaultUrlTransform(url)

Default URL sanitizer. Allows http, https, irc, ircs, mailto, xmpp protocols and relative URLs. Returns empty string for unsafe protocols.

Custom components

<script setup>
import VueMarkdown from 'vue-markdown'
import { h } from 'vue'

const components = {
  h1: (props) => h('h1', { class: 'title', ...props }, props.children),
  a: (props) => h('a', { target: '_blank', ...props }, props.children)
}
</script>

<template>
  <VueMarkdown children="# Click [here](https://example.com)" :components="components" />
</template>

Custom components receive a node prop containing the HAST element node.

Compatibility with react-markdown

This is a line-by-line translation of react-markdown v10.1.0. All pure logic functions (createProcessor, createFile, defaultUrlTransform, post) are identical. The only differences are Vue-specific adaptations:

  • elementAttributeNameCase: 'html' in toJsxRuntime call (required by Vue's JSX runtime)
  • Vue component model (defineComponent, defineAsyncComponent) instead of React function components
  • Vue Composition API (ref, computed, watchEffect) instead of React hooks
  • urlTransform: null skips URL processing entirely (react-markdown falls back to default)

Testing

npm test

58 tests total:

  • 26 property-based tests (fast-check) covering 15 correctness properties
  • 32 unit tests covering edge cases and integration

License

MIT

Acknowledgments

  • react-markdown - the original project this is ported from
  • unified ecosystem - the Markdown/HTML processing pipeline
  • Kiro AI IDE - AI-assisted development environment used to generate this project

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors