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

@cocoar/vue-markdown-editor

v2.14.0

Published

WYSIWYG Markdown editor for Vue 3 based on Milkdown, with Cocoar Design System styling

Readme

@cocoar/vue-markdown-editor

WYSIWYG Markdown editor for Vue 3 based on Milkdown (Kit approach), styled with the Cocoar Design System.

Markdown-first: lossless round-trip between markdown text and editor state. Shares the same remark stack as @cocoar/vue-markdown-core and <CoarMarkdown>.

Install

pnpm add @cocoar/vue-markdown-editor @cocoar/vue-ui

@cocoar/vue-ui and vue are peer dependencies. Milkdown is bundled as a regular dependency.

Then import the stylesheet once at your app's entry, alongside your other Cocoar styles:

/* app/main.css */
@import "@cocoar/vue-ui/styles";
@import "@cocoar/vue-markdown-editor/styles";

Or in your main.ts if you import CSS through JS:

import '@cocoar/vue-ui/styles'
import '@cocoar/vue-markdown-editor/styles'

Usage

<script setup lang="ts">
import { ref } from 'vue';
import { CoarMarkdownEditor } from '@cocoar/vue-markdown-editor';

const value = ref('# Hello\n\nStart typing **markdown**.');
</script>

<template>
  <CoarMarkdownEditor v-model="value" />
</template>

Toolbar Modes

  • floating (default) — appears on text selection, teleported to <body>, context-aware (text vs. table)
  • fixedCoarSidebar collapsed with icon buttons and flyout submenus
  • both — both active simultaneously
<CoarMarkdownEditor
  v-model="value"
  toolbar-mode="fixed"
  toolbar-position="left"
/>

Props

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string | '' | Markdown content (use with v-model) | | readonly | boolean | false | Disable editing | | placeholder | string | '' | Markdown hint shown while empty. Overlay-only — never written to modelValue | | toolbarMode | 'floating' \| 'fixed' \| 'both' | 'floating' | Toolbar layout | | toolbarPosition | 'left' \| 'right' | 'left' | Sidebar position when toolbarMode is 'fixed' or 'both' | | flavor | 'commonmark' \| 'gfm' \| 'cocoar' \| { gfm?, textColor? } | 'cocoar' | Portability contract — hard-enforces which features can be authored (see Flavors) | | uploadImage | (file: File) => Promise<{ url: string; alt?: string }> | undefined | Enables paste / drag-drop image upload (see Images) | | pickImage | (ctx: ImagePickContext) => void | undefined | Override the Insert Image button with your own asset picker (see Custom image source) |

Flavors (portability)

The flavor prop is a portability contract — it picks which features the editor offers and hard-enforces them (only the matching plugins are registered, so non-flavor constructs can't be typed or pasted; they degrade to plain text).

| Flavor | Adds on top of CommonMark | Renders in | |---|---|---| | 'commonmark' | (nothing — the portable floor) | any Markdown renderer (incl. minimal SwiftUI) | | 'gfm' | tables, task lists, strikethrough | GFM-capable renderers | | 'cocoar' (default) | inline text color (non-portable HTML) | the Cocoar viewer / your own renderer |

<CoarMarkdownEditor v-model="value" flavor="commonmark" />
<!-- or fine control -->
<CoarMarkdownEditor v-model="value" :flavor="{ gfm: true, textColor: false }" />

Pick the flavor that matches your strictest downstream renderer (e.g. a native SwiftUI Markdown view) and authors can't produce content it won't render. flavor is the hard format contract; the tools whitelist is soft toolbar curation within it. To change flavor on a live editor, re-key it (:key="flavor") so the plugin set re-registers.

Images

Images round-trip as standard Markdown — ![alt](url "title"). Three ways to add one:

  • Insert by URL — the Insert Image sidebar button opens a dialog for url / alt / title. Like the table/code-block buttons it lives in the sidebar, so use toolbar-mode="fixed" or "both".
  • Paste an image from the clipboard (e.g. a screenshot).
  • Drag & drop an image file into the writing area.

Paste and drop require an upload-image callback — it receives the File, stores it, and resolves with the resulting url. A spinner placeholder shows at the insertion point until it resolves, then is replaced by the image. Without the callback, image files fall through to the browser's default handling.

<CoarMarkdownEditor v-model="value" toolbar-mode="both" :upload-image="uploadImage" />

<script setup lang="ts">
async function uploadImage(file: File) {
  const url = await myAssetService.upload(file)
  return { url, alt: file.name }
}
</script>

Custom image source (pickImage)

Wire the Insert Image button to your own asset library / gallery with pickImage. When set it replaces the URL dialog — clicking the button calls it with a context bound to the cursor: insertImage(...) plus selectedText (a default for alt). Open your own modal and call ctx.insertImage(...) for each chosen image (it can stay open and insert several). The editor keeps all ProseMirror handling, so you never touch the selection.

<CoarMarkdownEditor v-model="value" toolbar-mode="both" :pick-image="openGallery" />

<script setup lang="ts">
function openGallery(ctx) {
  myGalleryModal.open({
    defaultAlt: ctx.selectedText,
    onPick: (asset) => ctx.insertImage({ url: asset.url, alt: asset.title }),
  })
}
</script>

pickImage (button) and uploadImage (paste / drop) are orthogonal and compose.

Resize / alignment / captions aren't part of standard Markdown and aren't supported yet — a richer image block is planned as a separate slice.

Events

| Event | Payload | Description | |---|---|---| | update:modelValue | string | Fired when markdown changes |